我的上一篇博客Hibernate缓存体系之查询缓存(query cache),以及list和iterate方法的差别介绍了查询缓存的概念,以及list和iterate的差别。读者可能注意到:那篇博客測试的前提是,仅仅开启查询缓存,没有开启二级缓存。
通过各种情形測试,我们能够得出一个结论:仅仅开启查询缓存。不开启二级缓存是没有意义的。
为什么这么说呢?上一篇博客能够看出。不开启二级缓存,iterate()方法存在N+1次数据库查询问题,list方法最多仅仅能命中id。也须要N次数据库查询,不管是哪儿种情况,查询缓存已经失去了意义。这篇博客我们开启二级缓存的情况下。将上篇博客的情况再測试下。看下会是什么效果。
hibernate4.1.6在hibernate.cfg.xml进行例如以下配置,能够开启二级缓存。
<property name="cache.use_second_level_cache">true</property> <property name="cache.region.factory_class">org.hibernate.cache.EhCacheRegionFactory</property>
因为測试代码和数据库都和上篇博客一模一样。唯一不同就是开启了二级缓存。这里不再附代码。直接通过測试结果来分析结论。
1. 2次list()运行结果分析
testUseList()运行结果例如以下:
Hibernate: select student0_.id as id0_, student0_.name as name0_, student0_.age as age0_ from Student student0_ where student0_.name=‘zhangsan111‘ list语句測试query cache:[email protected][id=1, name=zhangsan111, age=18] list语句測试query cache:[email protected][id=2, name=zhangsan111, age=18] list语句測试query cache:[email protected][id=3, name=zhangsan111, age=18] -------list进行第二次查询------ list语句測试query cache:[email protected][id=1, name=zhangsan111, age=18] list语句測试query cache:[email protected][id=2, name=zhangsan111, age=18] list语句測试query cache:[email protected][id=3, name=zhangsan111, age=18]
能够发现list()第一次发出1条sql语句。第二次查询没有訪问数据库,直接从缓存中获取的数据。在开启查询缓存和二级缓存的情况下,list将获取到的id放入查询缓存,key是sql语句。将实体对象放入二级缓存,key是实体对象的主键值。list会首先依据sql语句去查询缓存中获取id,假设没有获取到则发出1条sql查询语句,查询出全部须要的字段值。
2. 2次iterate()运行结果分析
testUseIterator()运行结果例如以下:
<span style="font-size:14px;">Hibernate: select student0_.id as col_0_0_ from Student student0_ where student0_.name=‘zhangsan111‘ Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, student0_.age as age0_0_ from Student student0_ where student0_.id=? iterate语句測试query cache:[email protected][id=1, name=zhangsan111, age=18] Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, student0_.age as age0_0_ from Student student0_ where student0_.id=? iterate语句測试query cache:[email protected][id=2, name=zhangsan111, age=18] Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, student0_.age as age0_0_ from Student student0_ where student0_.id=? iterate语句測试query cache:[email protected][id=3, name=zhangsan111, age=18] -------iterate进行第二次查询------ Hibernate: select student0_.id as col_0_0_ from Student student0_ where student0_.name=‘zhangsan111‘ iterate语句測试query cache:[email protected][id=1, name=zhangsan111, age=18] iterate语句測试query cache:[email protected][id=2, name=zhangsan111, age=18] iterate语句測试query cache:[email protected][id=3, name=zhangsan111, age=18]</span>
第一次iterate()查询,因为查询缓存和二级缓存中都没有数据,须要进行N+1次数据库查询;第二次查询,仅仅发出一条sql查询主键值,兴许依据主键值从二级缓存中获取具体信息。iterate方法会将获取到的实体对象存入二级缓存。至于是否会将id存入查询缓存,这里还不能确定,只是能够肯定的是。iterate不会利用查询缓存中的id值。而是每次查询都又一次使用sql查询满足条件的记录主键值。
之后再依据主键从二级缓存中查询实体对象。
3. 先iterate后list运行结果分析
testIteratorAndList1()运行结果例如以下:
<span style="font-size:14px;">Hibernate: select student0_.id as col_0_0_ from Student student0_ where student0_.name=‘zhangsan111‘ Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, student0_.age as age0_0_ from Student student0_ where student0_.id=? iterate语句測试query cache:[email protected][id=1, name=zhangsan111, age=18] Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, student0_.age as age0_0_ from Student student0_ where student0_.id=? iterate语句測试query cache:[email protected][id=2, name=zhangsan111, age=18] Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, student0_.age as age0_0_ from Student student0_ where student0_.id=? iterate语句測试query cache:[email protected][id=3, name=zhangsan111, age=18] -------第一次使用iterate,第二次使用list查询------ Hibernate: select student0_.id as id0_, student0_.name as name0_, student0_.age as age0_ from Student student0_ where student0_.name=‘zhangsan111‘ list语句測试query cache:[email protected][id=1, name=zhangsan111, age=18] list语句測试query cache:[email protected][id=2, name=zhangsan111, age=18] list语句測试query cache:[email protected][id=3, name=zhangsan111, age=18]</span>
这里能够看出,iterate的缓存信息对于list是没有帮助的。list会发出1条sql。从数据库中查询全部须要的字段值。这里能够看出:iterate方法不会将主键值放到查询缓存中,由于假设放入查询缓存的话。这里的list是没有必要再发出sql查询的。
4. 先list后iterate运行结果分析
testIteratorAndList2()运行结果例如以下:
<span style="font-size:14px;">Hibernate: select student0_.id as id0_, student0_.name as name0_, student0_.age as age0_ from Student student0_ where student0_.name=‘zhangsan111‘ list语句測试query cache:[email protected][id=1, name=zhangsan111, age=18] list语句測试query cache:[email protected][id=2, name=zhangsan111, age=18] list语句測试query cache:[email protected][id=3, name=zhangsan111, age=18] -------第一次使用list,第二次使用iterate查询------ Hibernate: select student0_.id as col_0_0_ from Student student0_ where student0_.name=‘zhangsan111‘ iterate语句測试query cache:[email protected][id=1, name=zhangsan111, age=18] iterate语句測试query cache:[email protected][id=2, name=zhangsan111, age=18] iterate语句測试query cache:[email protected][id=3, name=zhangsan111, age=18]</span>
这里可以得出的结论,跟2次list()查询几乎相同。
唯一的区别是:iterate每次查询都会发出查询实体对象id的sql语句。
5. 总结
通过开启查询缓存和二级缓存,相同的sql查询可以直接使用查询缓存中的id和二级缓存中的实体对象,可以有效的降低反复的数据库查询,可以提高查询效率。也就是说:同一时候开启查询缓存和二级缓存是有意义的。也是实际使用hibernate的最佳配置。
进一步的。我们也能够看出list和iterate方法的差别。list()会将实体对象的id放入查询缓存,将实体对象本身放入二级缓存。iterate不会将实体对象的id放入查询缓存。可是会将实体对象本身存入二级缓存。
假设第二次查询可以命中的情况下:list全然不须要查询数据库,可以先从查询缓存中获取到id。再从二级缓存中获取实体对象。iterate一定会发出一条查id的sql,然后去二级缓存中获取实体对象。
至此hibernate的二级缓存、查询缓存的关系已经讲完。list和iterate差别也已经測试出。
希望能对大家有帮助,假设错误。欢迎大牛们指正。