Hibernate中提供了两级缓存:
一级缓存是Session级别的缓存,它属于事务范围的缓存,该级缓存由hibernate管理,应用程序无需干预;
二级缓存是SessionFactory级别的缓存,该级缓存可以进行配置和更改,并且可以动态加载和卸载,
hibernate还为查询结果提供了一个查询缓存,它依赖于二级缓存;
一,缓存的概念
缓存是位于应用程序和永久性数据存储源之间用于临时存放复制数据的内存区域,缓存可以降低应用程序之间读写永久性数据存储源的次数,从而提高应用程序的运行性能;
hibernate在查询数据时,首先会到缓存中查找,如果找到就直接使用,找不到时才从永久性数据存储源中检索,
因此,把频繁使用的数据加载到缓存中,可以减少应用程序对永久性数据存储源的访问,使应用程序的运行性能得以提升;
二,缓存的范围
缓存范围决定了缓存的生命周期,缓存范围分为3类:
1>事务范围
缓存只能被当前事务访问,缓存的生命周期依赖于事务的生命周期,事务结束时,缓存的生命周期也结束了;
2>进程范围
缓存被进程内的所有事务共享,这些事务会并发访问缓存,需要对缓存采用必要的事务隔离机制,缓存的生命周期取决与进程的生命周期,进程结束,缓存的生命周期也结束了;
3>集群范围
缓存被一个或多个计算机的进程共享,缓存中的数据被复制到集群中的每个进行节点,进程间通过远程通信来保证缓存中数据的一致性;
在查询时,如果在事务范围内的缓存中没有找到,可以到进程范围或集群范围的缓存中查找,如果还没找到,则到数据库中查询;
Hibernate一级缓存
Hibernate一级缓存特点
a.使用一级缓存的目的是为了减少对数据库的访问次数,从而提升hibernate的执行效率;(当执行一次查询操作的时候,执行第二次查询操作,先检查缓存中是否有数据,
如果有数据就不查询数据库,直接从缓存中获取数据);
b.Hibernate中的一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数,只在session范围内有效,session关闭,一级缓存失败;
c.只在session范围有效,作用时间短,效果不是特别明显,在短时间内多次操作数据库,效果比较明显。
d.当调用session的save/saveOrUpdate/get/load/list/iterator方法的时候,都会把对象放入session缓存中;
e.一级缓存是默认启用的,你不能让他失效
验证一级缓存的存在
Transaction transaction = null; 2 Session session = null; 3 4 5 @Before 6 public void before() { 7 8 session = (Session) SessionFactoryUtil.getCurrentSession(); 9 //开启事务 10 transaction = session.beginTransaction(); 11 } 12 13 @Test 14 public void testCache1() { 15 Dept dept = (Dept) session.get(Dept.class, 1); 16 System.out.println("=============缓存分界线============="); 17 System.out.println("查询一样的数据"); 18 Dept dept2 = (Dept) session.get(Dept.class, 1); 19 System.out.println("==================================="); 20 System.out.println("查询不一样的数据"); 21 Dept dept3 = (Dept) session.get(Dept.class, 2); 22 } 23 24 25 @After 26 public void close() { 27 //提交食物 28 transaction.commit(); 29 }
验证一级缓存不能跨Session
/** * 证明一级缓存是不能跨Session */ @Test public void test11(){ Session session=HibernateUtil.getSession(); Transaction txx=session.beginTransaction(); Dept dept= (Dept) session.load(Dept.class,1); System.out.println(dept.getName()); HibernateUtil.closeSession(); System.out.println("========================"); Session session1=HibernateUtil.getSession(); Transaction txx1= session1.beginTransaction(); Dept dept1= (Dept) session1.get(Dept.class,1); System.out.println(dept1.getName()); txx1.commit(); HibernateUtil.closeSession(); }
证明iteration()N+1:
执行条件查询时,iterate()方法具有著名的 “n+1”次查询的问题,也就是说在第一次查询时iterate方法会执行满足条件的查询结果数再加一次(n+1)的查询。
但是此问题只存在于第一次查询时,在后面执行相同查询时性能会得到极大的改善。此方法适合于查询数据量较大的业务数据。
但是注意:当数据量特别大时(比如流水线数据等)需要针对此持久化对象配置其具体的缓存策略,比如设置其存在于缓存中的最大记录数、
缓存存在的时间等参数,以避免系统将大量的数据同时装载入内存中引起内存资源的迅速耗尽,反而降低系统的性能!!!
/** * 证明iteration()N+1 */ @Test public void test13(){ Session session=HibernateUtil.getSession(); String hql="from Dept"; Query query=session.createQuery(hql); Iterator<Dept> iterator=query.iterate(); while (iterator.hasNext()){ Dept dept=iterator.next(); System.out.println(dept.getName()); } System.out.println("======================"); HibernateUtil.closeSession(); }
可以看见第二次执行一样的查询语句是并没有生产新的SQL语句。这是因为第一次执行时会先去一级缓存中找数据如果没有的话在和数据库交互。然后把在数据库查询的结果放入到
一级缓存之中第二次在查询一样的数据时当走到一级缓存的时候直接使用不用在和数据交互。
执行原理图
HIbernate二级缓存
HIbernate二级缓存执行原理:
首先,当我们使用Hibernate从数据库中查询出数据,获取检索的数据后,Hibernate将检索出来的对象的OID放入缓存中key 中,然后将具体的POJO放入value中,
等待下一次再次向数据查询数据时,Hibernate根据你提供的OID先检索一级缓存,若有且配置了二级缓存,则检索二级缓存,如果还没有则才向数据库发送SQL语句,然后将查询出来的对象放入缓存中
HIbernate二级缓存概念
我们知道一级缓存,并且一级缓存的作用范围就在session中,每个session都有一个自己的一级缓存,而二级缓存也就是比一级缓存的作用范围更广,存储的内容更多,我们知道session是由sesssionFactory创建出来的,一个sessionFactory能够创建很多个session,每个session有自己的缓存,称为一级缓存,而sessionFactory也有自己的缓存,存放的内容供所有session共享,也就是二级缓存。
图解
Hibernate二级缓存配置
Hibernate二级缓存不同于一级缓存需要我们手动配置
1.pom文件引入需要的jar
<!--支持缓存的依赖包--> <!--hibernate配置需要的ehcahe插件--> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>3.6.10.Final</version> </dependency>
2.在cfg.xml文件配置相关节点
<!--添加缓存依赖-->
<!--开启二级缓存-->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
3.引入需要的缓存配置文件(resources文件夹下)
复制代码 <ehcache> <!-- 默认的临时文件--> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" memoryStoreEvictionPolicy="LRU" /> </ehcache> 复制代码
一级缓存,二级缓存都有相应的清除方法。
其中二级缓存提供的清除方法为:
按对象class清空缓存
按对象class和对象的主键id清空缓存
清空对象的集合中的缓存数据等。
适合使用的情况
并非所有的情况都适合于使用二级缓存,需要根据具体情况来决定。同时可以针对某一个持久化对象配置其具体的缓存策略。
总之是根据不同的业务情况和项目情况对hibernate进行有效的配置和正确的使用,扬长避短。不存在适合于任何情况的一个“万能”的方案。