Hibernate——缓存

一、对象状态

参考:https://mp.weixin.qq.com/s/VFnny3ou48w9bIgTT0xVow

1.1 临时/瞬时状态

含义:直接new出来的对象就是临时/瞬时状态的。
特点:
——该对象还没有被持久化【没有保存在数据库中】
——不受Session的管理

User user = new User();
IdCard idCard = new IdCard();
// 这样,对象处于临时/瞬时状态了

1.2 持久化状态

含义:当保存在数据库中的对象就是持久化状态。
当调用session的save/saveOrUpdate/get/load/list等方法时,对象就是持久化状态
特点:
——在数据库有对应的数据
——受Session的管理
——当对对象属性进行更改的时候,会反映到数据库中!

session.save(idCard);
transaction.commit();
// 这样,对象处于持久化状态了。

1.3 游离状态

含义:当Session关闭了以后,持久化的对象就变成了游离状态了。
特点:
——在数据库有对应的数据
——不处于session的管理

session.save(idCard);
transaction.commit();
session.close();
// 这样,对象处于游离状态了。

二、一级缓存

2.1 含义

项目含义
Hibenate中一级缓存也叫做session的缓存。
目的在session范围内,减少对数据库的访问次数!从而提升hibernate的执行效率!
有效范围session。 Session关闭,一级缓存失效!

注意
1、持久化状态的对象,都受Session管理,都会在Session缓存中!
2、Session的缓存由hibernate维护,用户不能操作缓存内容。
3、 若想操作缓存内容,必须通过hibernate提供的evit/clear方法操作。

示例说明:
1、更新数据库
已知:user表中(id = 1,username=“张珊”)。
目的:把id=1的username改为“张珊”。

// 获取id=1的对象信息。
User user = (User)session.get(User.class,1);
// 修改username为“张珊”。
user.setUsername("张珊");
// 提交事务。
transaction.commit();
// 关闭session。
session.close();

结果:只有一条查询SQL,并没有更新SQL。
原因:查询的结果被缓存了。修改后的数据与缓存的数据一样,所以没有执行更新操作。
2、获取数据
已知:user表中(id = 1,username=“张珊”)。
目的:二次获取该信息。

User user = null;
user = (User)session.get(User.class,1); // 一次获取
user = (User)session.get(User.class,1);// 二次获取
// 提交事务。
transaction.commit();
// 关闭session。
session.close();

结果:只有一条查询SQL。
原因:一次查询的结果被缓存了。 二次获取直接从缓存中获取。

2.2 缓存相关的方法

常用的方法作用
session.flush();让一级缓存与数据库同步
session.evict(arg0);清空一级缓存中指定的对象
session.clear();清空一级缓存中缓存的所有对象

2.2.1 clear

 User user = null;
user = (User) session.get(User.class, 1);
//清除缓存,那么下面获取的时候,就不能从缓存里面拿了
session.clear();
user = (User) session.get(User.class, 1);
// 结果:执行两次查询语句。

2.2.2 flush

在有缓存的情况下,修改同一条记录的数据,以最后的为准…因此只有一条update

User user = null;
user = (User) session.get(User.class, 1);
user.setUsername("李四");
user = (User) session.get(User.class, 1);
user.setUsername("王五");
// 结果:执行一次更新SQL语句。

强制让它和数据库同步的话,就有两条update了

User user = null;
user = (User) session.get(User.class, 1);
user.setUsername("李四");
session.flush();
user = (User) session.get(User.class, 1);
user.setUsername("王五");
// 结果:执行两次更新SQL语句。

2.2.3 方法适用场景

一般地,我们在批处理的时候会用,因为缓存也是有大小的。
思路:
——每隔一定记录数,先与数据库同步 flush()
——再清空缓存 clear()
注意:不同的Session是不会共享缓存的!

2.3 Iterator与list

使用HQL查询全部数据的时候,可以使用list()得到所有的数据,也可以使用iterator()得到一个迭代器,再遍历迭代器。
二者都可以获取缓存的数据。

2.4 懒加载

含义:当使用数据的时候才去获取数据、执行对应的SQL语句…当还没用到数据的时候,就不加载对应的数据!
作用:提高Hibernate的性能,提高执行效率!
——get: 及时加载,只要调用get方法立刻向数据库查询
——load:默认使用懒加载,当用到数据的时候才向数据库查询。

user = (User) session.get(User.class, 1);
user = (User) session.load(User.class, 1);

2.4.1 修改懒加载

<class name="IdCard" table="IdCard" lazy="false">

属性值:
true 使用懒加载
false 关闭懒加载
extra (在集合数据懒加载时候提升效率)【只有在set、list等集合标签中使用】
——在真正使用数据的时候才向数据库发送查询的sql;
——如果调用集合的size()/isEmpty()方法,只是统计,不真正查询数据!

2.4.2 懒加载异常

当Session关闭后,就不能使用懒加载了,否则会报出异常。

session.close();
System.out.println(user);
// 结果:报出异常。
异常解决方法含义示例
方式1先使用一下数据dept.getDeptName();
方式2强迫代理对象初始化Hibernate.initialize(dept);
方式3关闭懒加载设置lazy=false;
方式4在使用数据之后,再关闭session!

三、二级缓存

3.1 含义

项目含义
来源Hibernate自带
含义基于应用程序的缓存
范围所有的Session都可以使用
存储内容存储的是常用的类

注意:Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!
——若想用二级缓存,只需在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影响代码。
——若觉得hibernate提供的框架框架不好用,自己可以换其他的缓存框架或自己实现缓存框架都可以。

3.2 配置二级缓存

二级缓存是Hibernate自带的,可以在hibernate.properties文件中找到对应的信息。
hibernate.properties:

#hibernate.cache.use_second_level_cache false【二级缓存默认不开启,需要手动开启】
#hibernate.cache.use_query_cache true      【开启查询缓存】
## choose a cache implementation        【二级缓存框架的实现】
#hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider
hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider 默认实现
#hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider
#hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider

配置步骤:
1)开启二级缓存
2)指定缓存框架
3)指定哪些类加入二级缓存

3.2.1 开启二级缓存

在hibernate.cfg.xml文件中开启二级缓存

<!-- a.  开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>

3.2.2 指定缓存框架

指定Hibernate自带的二级缓存框架就好了

  <!-- b. 指定使用哪一个缓存框架(默认提供的) -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>

3.2.3 指定哪些类加入二级缓存

<!-- c. 指定哪一些类,需要加入二级缓存 -->
<class-cache usage="read-write" class="com.my.entity.Monkey"/>
<class-cache usage="read-only" class="com.my.entity.Cat"/>

3.2.4 测试

一级缓存是Session的缓存,那么我们在测试二级缓存的时候使用两个Session来测试就好了。如果第二个Session拿到的是缓存数据,那么就证明二级缓存是有用的。

public static void testCache2() {

	Session session1 = getSession();
	Transaction transaction = session1.getTransaction();
	transaction.begin();
	Monkey monkey = (Monkey) session1.get(Monkey.class,"40283f815be67f42015be67f43240001" );
	System.out.println(monkey.getName());
	
	Session session2 = factory.openSession();
	Transaction transaction2 = session2.getTransaction();
	transaction2.begin();
	Monkey monkey2 = (Monkey) session1.get(Monkey.class, "40283f815be67f42015be67f43240001");
	System.out.println(monkey2.getName());
	
	//提交事务
	transaction.commit();
	transaction2.commit();
	//关闭Session
	session1.close();
	session2.close();
}

结果:只有一个查询语句。输出正确结果。说明二级缓存生效。

3.3 二级缓存策略

<!-- c. 指定哪一些类,需要加入二级缓存 -->
<class-cache usage="read-write" class="com.my.entity.Monkey"/>
<class-cache usage="read-only" class="com.my.entity.Cat"/>
属性值含义
read-only放入二级缓存的对象,只读;
read-write放入二级缓存的对象,可以读、写;

非严格的读写
(基于事务的策略)

3.4 集合缓存

问题:在数据库查询的数据是集合时,Hibernate默认是没有为集合数据设置二级缓存的。因此,还需要去读写数据库的信息。

3.4.1 集合配置二级缓存

在hibernate.cgf.xml中配置对象中的集合为二级缓存。

<!-- 集合缓存[集合缓存的元素对象,也加加入二级缓存] -->
<collection-cache usage="read-write" collection="cn.itcast.b_second_cache.Dept.emps"/>

3.4.2 测试

public static void testCache() {

	Session session1 = sf.openSession();
	session1.beginTransaction();
	// a. 查询一次
	Dept dept = (Dept) session1.get(Dept.class, 10);
	dept.getEmps().size();// 集合
	session1.getTransaction().commit();
	session1.close();
	
	System.out.println("------");
	
	// 第二个session
	Session session2 = sf.openSession();
	session2.beginTransaction();
	// a. 查询一次
	dept = (Dept) session2.get(Dept.class, 10);  // 二级缓存配置好; 这里不查询数据库	
	dept.getEmps().size();
	session2.getTransaction().commit();
	session2.close();
}

3.5 查询缓存

问题:list()和iterator()会把数据放在一级缓存,但一级缓存只在Session的作用域中有效。如果想要跨Session来使用,就要设置查询缓存

1、默认的查询数据是不放在二级缓存中的。
2、若想把查询数据放到二级缓存,就需要在配置文件中开启。

 <!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>

在使用程序查询的时候,也要调用setCacheable()方法,设置为查询缓存。

public static void listCache() {

	Session session1 = sf.openSession();
	session1.beginTransaction();
	// HQL查询  【setCacheable  指定从二级缓存找,或者是放入二级缓存】
	Query q = session1.createQuery("from Dept").setCacheable(true);
	System.out.println(q.list());
	session1.getTransaction().commit();
	session1.close();

	Session session2 = sf.openSession();
	session2.beginTransaction();
	q = session2.createQuery("from Dept").setCacheable(true);
	System.out.println(q.list());  // 不查询数据库: 需要开启查询缓存
	session2.getTransaction().commit();
	session2.close();
	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值