Hibernate 二级缓存
来源:互联网 发布:做淘宝需要做什么推广 编辑:程序博客网 时间:2024/05/29 15:56
二级缓存需要sessionFactory来管理,它是进初级的缓存,所有人都可以使用,它是共享的。
二级缓存比较复杂,一般用第三方产品。hibernate提供了一个简单实现,用Hashtable做的,只能作为我们的测试使用,商用还是需要第三方产品。
使用缓存,肯定是长时间不改变的数据,如果经常变化的数据放到缓存里就没有太大意义了。因为经常变化,还是需要经常到数据库里查询,那就没有必要用缓存了。
hibernate做了一些优化,和一些第三方的缓存产品做了集成。老师采用EHCache缓存产品。
和EHCache二级缓存产品集成:EHCache的jar文件在hibernate的lib里,我们还需要设置一系列的缓存使用策略,需要一个配置文件ehcache.xml来配置。这个文件放在类路径下。
//默认配置,所有的类都遵循这个配置
<defaultCache
//缓存里可以放10000个对象
maxElementsInMemory="10000"
//过不过期,如果是true就是永远不过期
eternal="false"
//一个对象被访问后多长时间还没有访问就失效(120秒还没有再次访问就失效)
timeToIdleSeconds="120"
//对象存活时间(120秒),如果设置永不过期,这个就没有必要设了
timeToLiveSeconds="120"
//溢出的问题,如果设成true,缓存里超过10000个对象就保存到磁盘里
overflowToDisk="true"
/>
我们也可以对某个对象单独配置:
<cache name="com.bjpowernode.hibernate.Student"
maxElementsInMemory="100"
eternal="false"
timeToIdleSeconds="10000"
timeToLiveSeconds="10000"
overflowToDisk="true"
/>
还需要在hibernate.cfg.xml配置文件配置缓存,让hibernate知道我们使用的是那个二级缓存。
<!-- 配置缓存提供商 -->
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider</property>
<!-- 启用二级缓存,这也是它的默认配置 -->
<property name="hibernate.cache.use_second_level_cache">
true</property>
启用二级缓存的配置可以不写的,因为默认就是true开启二级缓存。
必须还手动指定那些实体类的对象放到缓存里在hibernate.cfg.xml里:
//在<sessionfactory>标签里,在<mapping>标签后配置
<class-cache class="com.bjpowernode.hibernate.Student"
usage="read-only"/>
或者在实体类映射文件里:
//在<class>标签里,<id>标签前配置
<cache usage="read-only"/>
usage属性表示使用缓存的策略,一般优先使用read-only,表示如果这个数据放到缓存里了,则不允许修改,如果修改就会报错。这就要注意我们放入缓存的数据不允许修改。因为放缓存里的数据经常修改,也就没有必要放到缓存里。
使用read-only策略效率好,因为不能改缓存。但是可能会出现脏数据的问题,这个问题解决方法只能依赖缓存的超时,比如上面我们设置了超时为120秒,120后就可以对缓存里对象进行修改,而在120秒之内访问这个对象可能会查询脏数据的问题,因为我们修改对象后数据库里改变了,而缓存却不能改变,这样造成数据不同步,也就是脏数据的问题。
第二种缓存策略read-write,当持久对象发生变化,缓存里就会跟着变化,数据库中也改变了。这种方式需要加解锁,效率要比第一种慢。
还有两种策略,请看hibernate文档,最常用还是第一二种策略。
二级缓存测试代码演示:注意上面我们讲的两个session分别调用load方法查询相同的数据,第二个session的load方法还是发了sql语句到数据库查询数据,这是因为一级缓存只在当前session中共享,也就是说一级缓存不能跨session访问。
//开启二级缓存,二级缓存是进程级的缓存,可以共享
//两个session分别调用load方法查询相同的实体对象
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Student student = (Student)session.load(Student.class, 1);
System.out.println("student.name=" + student.getName());
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Student student = (Student)session.load(Student.class, 1);
//不会发出查询语句,因为配置二级缓存,session可以共享二级缓存中的数据
//二级缓存是进程级的缓存
System.out.println("student.name=" + student.getName());
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
如果开启了二级缓存,那么第二个session调用的load方法查询第一次查询的数据,是不会发出sql语句查询数据库的,而是去二级缓存中取数据。
//开启二级缓存
//两个session分别调用get方法查询相同的实体对象
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Student student = (Student)session.get(Student.class, 1);
System.out.println("student.name=" + student.getName());
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Student student = (Student)session.get(Student.class, 1);
//不会发出查询语句,因为配置二级缓存,session可以共享二级缓存中的数据
//二级缓存是进程级的缓存
System.out.println("student.name=" + student.getName());
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
注意:二级缓存必须让sessionfactory管理,让sessionfactory来清除二级缓存。sessionFactory.evict(Student.class);//清除二级缓存中所有student对象,sessionFactory.evict(Student.class,1);//清除二级缓存中id为1的student对象。
如果在第一个session调用load或get方法查询数据后,把二级缓存清除了,那么第二个session调用load或get方法查询相同的数据时,还是会发出sql语句查询数据库的,因为缓存里没有数据只能到数据库里查询。
我们查询数据后会默认自动的放到二级和一级缓存里,如果我们想查询的数据不放到缓存里,也是可以的。也就是说我们可以控制一级缓存和二级缓存的交换。
session.setCacheMode(CacheMode.IGNORE);禁止将一级缓存中的数据往二级缓存里放。
还是用上面代码测试,在第一个session调用load方法前,执行session.setCacheMode(CacheMode.IGNORE);这样load方法查询的数据不会放到二级缓存里。那么第二个session执行load方法查询相同的数据,会发出sql语句到数据库中查询,因为二级缓存里没有数据,一级缓存因为不同的session不能共享,所以只能到数据库里查询。
上面我们讲过大批量的数据添加时可能会出现溢出,解决办法是每当天就20个对象后就清理一次一级缓存。如果我们使用了二级缓存,光清理一级缓存是不够的,还要禁止一二级缓存交互,在save方法前调用session.setCacheMode(CacheMode.IGNORE)。
二级缓存也不会存放普通属性的查询数据,这和一级缓存是一样的,只存放实体对象。session级的缓存对性能的提高没有太大的意义,因为生命周期太短了。
- hibernate 二级缓存
- hibernate 二级缓存
- hibernate二级缓存
- Hibernate二级缓存
- hibernate二级缓存
- hibernate 二级缓存
- Hibernate 二级缓存
- hibernate二级缓存
- Hibernate二级缓存
- hibernate二级缓存
- Hibernate二级缓存
- Hibernate 二级缓存
- hibernate二级缓存
- hibernate 二级缓存
- hibernate 二级缓存
- Hibernate二级缓存
- hibernate 二级缓存
- Hibernate二级缓存
- 黑马程序员_java基础知识总结(3)集合框架
- [个人开发者赚钱八] 格局决定事业,思维决定出路
- 无法引入import com.sun.management.OperatingSystemMXBean
- hiberante学习笔记7 配置文件常用属性
- 黑马程序员_java高新(四)_类加载器、动态代理
- Hibernate 二级缓存
- php常量及变量定义方法
- 数据结构栈C++简单实现
- 失败了一天啊!
- POJ1328 Radar Installation 贪心
- lua 解析 xml 文件,含内嵌
- CentOS安装SNMP
- Eclipse Kepler SR2 设置 每次打开选择工作区
- 黑马程序员_String类