Hibernate二级级缓存
上篇介绍了[Hibernate](http://blog.csdn.net/lovesummerforever/article/details/20997879)[一级缓存](http://blog.csdn.net/lovesummerforever/article/details/20997879),主要是session缓存,session生命周期结束,缓存也就结束。二级缓存相对于一级缓存来说是一个范围更广阔一些,就比你住的地方周围有多个小卖铺(session缓存),和一个大型超市,原料加工厂送货的时候送小卖铺一份的同时,必然送一份到超市。而给第二个小卖铺送一份的同时,也送给超市一份,这个超市就是我们的SessionFactory。hibernate二缓存的又称为“SessionFactory的缓存”缓存的生命周期和SessionFactory(线程安全,一个数据库对应一个,重量级)的生命周期一致,所以SessionFactory可以管理二级缓存。
下面来看session控制的二级缓存。
### 二级缓存配置
1、需要引入第三方的jar包,hibernate的Cglib.jar。
2、在缓存的配置文件来控制缓存,我们可以拷贝hibernate已有项目中的ehcache.xml配置文件到自己的项目中。通过这个文件,我们可以对二级缓存进行设置,例如缓存的时间,缓存的代销,缓存间隔多长时间自动被清掉,缓存超时间直接缓存到磁盘指定的位置上等设置。
3、在hibernate.cfg.xml文件中加入缓存产品提供商。
~~~
<propertyname="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
~~~
4、启用二级缓存,设置为true,默认是true,添加上有助于我们手动关闭和开启二级缓存。
~~~
<propertyname="hibernate.cache.use_second_level_cache">true</property>
~~~
5、指定哪些实体类使用二级缓存。
方法一:在对应实体的.hbm.xml文件中设置,<cacheusage="read-only"/>这样如果我们想要知道二百个映射文件哪些使用了二级缓存,就要查看二百个文件,所以我们可以把对实体加入二级缓存的策略放到hibernate.cfg.xml进行配置。也就是方法二。
方法二:处于好管理的目的我们把哪个实体使用二级缓存的配置放到hibernate.cfg.xml文件中。例如执行把student实体加入二级缓存策略。 <!--
指定Student使用二级缓存
-->
~~~
<class-cacheclass="com.bjpowernode.hibernate.Student"usage="read-only"/>
~~~
注意:缓存策略通常采用read-only和read-write
缓存原则;通常是读大于写的数据进行缓存。
### 开启二级缓存在两个session中使用两次load()进行查询
代码如下所示。
~~~
/**
* 开启二级缓存
*
* 在两个session中发load查询
*/
public voidtestCache1() {
Sessionsession = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Studentstudent = (Student)session.load(Student.class, 1);
System.out.println("student.name=" +student.getName());
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Studentstudent = (Student)session.load(Student.class, 1);
//不会发出查询语句,因为配置二级缓存,session可以共享二级缓存中的数据
//二级缓存是进程级的缓存
System.out.println("student.name=" +student.getName());
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
打印结果如下图所示。
![](https://box.kancloud.cn/2016-06-21_576908fa7ec3a.jpg)
由此可知,虽然我们使用的是两个session,但第二次查询的时候没有再向数据库发出查询语句。也就是第一次查询的时候放入session的同时也放入SessionFactory缓存中一份,而第二个session再查询的时候,就直接从二级缓存中取出就可以了。
### 开启二级缓存在两个session中使用两次get()进行查询。
代码就是把上述代码load方法改动为get方法。
运行结果如下所示。
![](https://box.kancloud.cn/2016-06-21_576908fa7ec3a.jpg)
同load一样,对于sessionFactory级别的缓存,第二次查询时就不再向数据库发出查询sql命令。
### 开启二级缓存,在两个session中发出load查询,采用SessionFactory管理二级缓存
代码如下所示。
~~~
/**
* 开启二级缓存
*
* 在两个session中发load查询,采用SessionFactory管理二级缓存
*/
public voidtestCache3() {
Sessionsession = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
Studentstudent = (Student)session.load(Student.class, 1);
System.out.println("student.name=" +student.getName());
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
//管理二级缓存 (evict清除的意思)
//HibernateUtils.getSessionFactory().evict(Student.class);
HibernateUtils.getSessionFactory().evict(Student.class, 1);
try {
session= HibernateUtils.getSession();
session.beginTransaction();
Studentstudent = (Student)session.load(Student.class, 1);
//会发出查询语句,因为二级缓存中的数据被清除了
System.out.println("student.name=" +student.getName());
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
显示结果如下所示。
![](https://box.kancloud.cn/2016-06-21_576908fa981c3.jpg)
根据显示结果可知,在两个session中发出load查询,第一次放入session缓存同时放入了二级缓存sessionFactory中。在第二个session中,首先使用SessionFactory对二级缓存管理,使用evict()方法清除二级缓存,所以第二个session采用load查询时,需要重新向数据库发送sql命令。
### 一级缓存和二级缓存交互
代码如下所示。
~~~
public voidtestCache4() {
Sessionsession = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
//禁止将一级缓存中的数据放到二级缓存中。缓存模式设置为忽略。
session.setCacheMode(CacheMode.IGNORE);
Studentstudent =(Student)session.load(Student.class, 1);
System.out.println("student.name=" + student.getName());
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
try {
session= HibernateUtils.getSession();
session.beginTransaction();
Studentstudent = (Student)session.load(Student.class, 1);
//会发出查询语句,因为禁止了一级缓存和二级缓存的交互,一级缓存没有放到二级缓存中。
System.out.println("student.name=" +student.getName());
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
显示结果如下所示。
![](https://box.kancloud.cn/2016-06-21_576908fa981c3.jpg)
从上图可以看出,首先我们开启session的事务,然后设置了当写入session缓存中的同时不写入二级缓存,session.setCacheMode(CacheMode.IGNORE),这样第二个session再查询的时候就不能从二级缓存中找到相应的内容,仍需向数据库发出sql请求。
### 大批量数据的添加。
当添加或更新大批量数据的时候,为了防止缓存中数据量过大,我们可以设置删除session一级缓存,如果此时开启二级缓存,那么也会同样再二级缓存中存放一份,这样的话很可能会导致缓存的溢出,所以对于大数据来说,如果放入了一级缓存中,就应该禁止再放入二级缓存中。
代码如下所示。
~~~
/**
* 大批量的数据添加
*/
public voidtestCache5() {
Sessionsession = null;
try {
session= HibernateUtils.getSession();
session.beginTransaction();
//禁止一级缓存和二级缓存交互
session.setCacheMode(CacheMode.IGNORE);
for (int i=0;i<100; i++) {
Studentstudent = new Student();
student.setName("张三" +i);
//一级缓存放一份,二级缓存也放一份。
session.save(student);
//每20条更新一次
if (i %20 == 0) {
session.flush();
//清除缓存的内容
//只清除了一级缓存中的内容,没有清除一级缓存中的内容。如果数据量过大,一样溢出。
//大于大数据量来说,如果配置了一级缓存的话,就应该禁止再放入二级缓存中。
session.clear();
}
}
session.getTransaction().commit();
}catch(Exceptione) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
~~~
控制台打印sql如下图所示。
![](https://box.kancloud.cn/2016-06-21_576908fa5c8c0.jpg)
### Hibernate二级缓存总结
从上可知,二级缓存时比一级缓存作用域更大,是在整个应用程序中。一级缓存是不能被卸载的,是必需的,不允许也无法卸载,它是事务范围的缓存。而二级缓存是可配置的,可卸载的,SessionFactory生命周期和应用程序整个过程对应,就有可能出现并发问题。
什么样的数据适合放到二级缓存中?
1、很少被修改的数据
2、不是很重要的,并允许出现偶尔的并发数据
3、不会被并发的数据
4、常量数据
什么样的数据适不合放到二级缓存中?
1、经常被修改的数据。
2、绝对不允许并发的数据。
3、与其他应用共享的数据。
- 前言
- Struts旅程(一)Struts简介和原理
- struts旅程(二)Struts登录示例
- Struts旅程(三)Struts表单处理器ActionForm(静态动态)
- Struts旅程(四)MVC向struts MVC框架演变过程
- Struts旅程(五)struts控制器DispatchAction
- Struts旅程(六)Struts页面转发控制ActionForward和ActionMapping
- Hibernate旅程(一)Hibernate架构概述
- Hibernate旅程(二)Hibernate实例
- Hibernate旅程(三)Hibernate持久化对象的三个状态
- Hibernate旅程(四)Hibernate对数据库删除、查找、更新操作
- Hibernate旅程(五)Hibernate映射--基本类映射和对象关系映射
- Hibernate旅程(六)Hibernate映射--继承映射
- Hibernate旅程(七)Hibernate缓存机制--一级缓存
- Hibernate旅程(八)Hibernate缓存机制--二级缓存
- Hibernate旅程(九)Hibernate缓存机制--查询缓存
- Spring旅程(一)为什么使用Spring
- Spring旅程(二)非Spring向Spring过渡-- Spring IOC容器的使用
- Spring旅程(三) AOP--Spring AOP容器基础
- Spring旅程(四) AOP--Spring AOP实例
- SSH旅程(五)Spring运用到Hibernate中
- SSH旅程(六)Spring和struts结合(方案一)