前述
缓存在操作系统中经常被使用,在CPU和内存之间有高速cache。在内存读取硬盘的时候也有缓存,也有相应的缓存页面置换算法: FIFO(First In First Out)先进先出、LRU(Least Recently Used)最近很少使用、 LFU(Least Frequently Used)最近不常被使用(命中率低)。在Hibernate中也有使用一级缓存和二级缓存来加快读取数据库的操作,节省开销。
一级缓存
一级缓存,又称为session级别的缓存。当获得一次会话,hibernate在session中创建多个集合(Map),用于存放操作数据(PO对象),为程序优化服务,如果之后需要相应的数据,hibernate优先从session缓存中获取,如果有就使用,没有再查询。
- 缓存工作原理

- 一级缓存是默认的,查询都将数据存放在一级缓存中。
- 一级缓存缓存的是对象本身。
- 一级缓存常用的API
evict():用于对某个对象从session的一级缓存中清除
clear():将一级缓存中所有对象全部清除
flush():刷新一级缓存区的内容,使之与数据库数据保持同步。
注意: 常用的Query方法中,query.list()是不使用一级缓存的,每次都是重新查询数据库的。
一级缓存的操作
//1 查询 id = 1
User user = (User) session.get(User.class, 1);
System.out.println(user);
//2 再查询 -- 不执行select语句,将从一级缓存获得
User user2 = (User) session.get(User.class, 1); //此时 user 与user2是同一个对象
清除缓存
User user = (User) session.get(User.class, 1);
System.out.println(user);
//清除
//session.clear();
session.evict(user);
// 一级缓存没有缓存对象,从数据库直接查询
User user2 = (User) session.get(User.class, 1);
System.out.println(user2); //此时user 与 user2 为两个不同对象
一级缓存的快照(备份)
快照:与一级缓存一样的存放位置,对一级缓存数据备份。保证数据库的数据与一级数据缓存必须一致。如果一级缓存修改,在执行commit提交时,将自动刷新一级缓存,执行update语句,将一级缓存保存到数据库中。
- 问题:一级缓存什么时候刷新?能否修改刷新时机?
默认情况下,执行commit()时。当修改了一级缓存后,三种情况:session查询,手动刷新flush,commit底层自动flush
二级缓存
使用annotation配置缓存:
1 | @Entity |
缓存策略(CacheConcurrencyStrategy)的取值
- 只读缓存(Strategy:read only)(常用)
如果你的应用程序只需读取一个持久化类的实例,而无需对其修改, 那么就可以对其进行只读 缓存。这是最简单,也是实用性最好的方法。甚至在集群中,它也能完美地运作。 - 读写/缓存(Strategy:read/write)(常用)
如果应用程序需要更新数据,那么使用读/写缓存 比较合适。 如果应用程序要求“序列化事务”的隔离级别(serializable transaction isolation level),那么就决不能使用这种缓存策略。 如果在 JTA 环境中使用缓存,你必须指定 hibernate.transaction.manager_lookup_class 属性的值, 通过它,Hibernate 才能知道该应用程序中 JTA 的TransactionManager的具体策略。 在其它环境中,你必须保证在 Session.close()、或 Session.disconnect() 调用前, 整个事务已经结束。 如果你想在集群环境中使用此策略,你必须保证底层的缓存实现支持锁定(locking)。Hibernate 内置的缓存策略并不支持锁定功能。 - 非严格读/写缓存(Strategy:nonstrict read/write)
如果应用程序只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离,那么比较适合使用非严格读/写缓存策略。如果在 JTA 环境中使用该策略,你必须为其指定 hibernate.transaction.manager_lookup_class 属性的值,在其它环境中,你必须保证在Session.close()、或 Session.disconnect() 调用前,整个事务已经结束。 - 事务缓存(transactional)
Hibernate 的事务缓存策略提供了全事务的缓存支持,例如对 JBoss TreeCache 的支持。这样的缓存只能用于 JTA 环境中,你必须指定为其 hibernate.transaction.manager_lookup_class 属性。region的取值
在ehcache.xml中,可以自定义缓存类型,比如:1
2
3
4
5
6
7<cache name="sampleCache1"
maxElementsInMemory="10000" //最大缓存数量
eternal="false" //是否能被清除
timeToIdleSeconds="300" //300秒没被访问就被清除
timeToLiveSeconds="600" //已经存在600秒就可以被清除
overflowToDisk="true" //溢出时放在硬盘上
/>
那么@region=”sampleCache1”
配置文件中:
//不使用二级缓存
//hibernate中默认的二级缓存ehcache
//启用查询缓存
- load默认使用二级缓存,iterate默认使用二级缓存
- list默认往二级缓存加数据,但是查询的时候不使用
- 如果要query用二级缓存,需打开查询缓存
true
调用Query的setCachable (true)方法指明使用二级缓存
例如:session.createQuery(“from Category”).setCacheable(true).list();