对于JPA2.0,缓存分为一级缓存和二级缓存(JPA1.0只支持一级缓存)。二级缓存通常是用来提高应用程序性能的,它可以避免访问以已经从数据库加载的数据,提高访问未被修改数据对象的速度。
持久化上下文就是JPA的一级缓存,通过在持久化上下文中存储持久化状态实体的快照,既可以进行脏检测,还可以当做持久化实体的缓存。一级缓存属于请求范围级别的缓存,如下
JPA二级缓存是跨越持久化上下文的,是真正意义上的全局应用缓存,如下
如果二级缓存激活,JPA会先从一级缓存中寻找实体,未找到再从二级缓存中寻找。当二级缓存有效时,就不能依靠事务来保护并发的数据,而是依靠锁策略,如在确认修改后,需要手工处理乐观锁失败等。
注意:二级缓存只能缓存通过EntityManager的find或getReference查询到的实体,以及通过实体的getter方法获取到的关联实体;而不能缓存通过JPQL查询获得的数据。
二级缓存通常用来提高性能,同时,使用二级缓存可能会导致提取到“陈旧”数据,也会出现并发写的问题。所以二级缓存最好是用在经常阅读数据,比较少更新数据的情况,而不应该对重要数据使用二级缓存。
对于不同的JPA实现产品,开启二级缓存的方式会有所不同,下面以 Spring+Hibernate为例,开启二级缓存,步骤如下
1) 添加hibernate-ehcache.jar文件,推荐使用maven来管理;
2) 修改Spring配置文件,开启二级缓存
3) 将需要缓存的实体类标注@ javax.persistence.Cacheable或org.hibernate.annotations.Cache。
采用@javax.persistence.Cacheable配置,开启二级缓存如下
注意:
u 实体上标注@cacheable时,需要设置javax.persistence.sharedCache.mode属性值;
u javax.persistence.sharedCache.mode
值可以为ENABLE_SELECTIVE(推荐值)、DISABLE_SELECTIVE、NONE、ALL;
若为ENABLE_SELECTIVE,则只要添加@Cacheable注解的实体才会被缓存;
若为DISABLE_SELECTIVE,则标注@Cacheable(value=false)的实体才被缓存;
若为NONE,任何实体都不会被缓存,即使被@Cacheable标注;
若为ALL,实体都会被缓存,即使没有@Cacheable标注;
u 开启Hibernate的查询缓存
除了设置
key="hibernate.cache.use_query_cache">true
外,还需要在JPA查询时采用@QueryHint来实现查询缓存,如下
public interface DictDao
{
// 通过@QueryHint来实现查询缓存。
@QueryHints({@QueryHint(name = "org.hibernate.cacheable", value ="true")})
List
}
采用org.hibernate.annotation.Cache配置时,设置如下:
采用@cache时,除了在实体上标注@Cache外,还需要添加ehcache.xml配置文件,如下
xsi:noNamespaceSchemaLocation="ehcache.xsd">
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="180"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"
/>
maxElementsInMemory="100"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="180"
overflowToDisk="true" />
maxElementsInMemory="100"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="180"
overflowToDisk="false" />
注意:
u Hibernate3.x与Hibernate4.x开启二级缓存设置不同
Hibernate4.x:
org.hibernate.cache.ehcache.EhCacheRegionFactory
Hibernate3.x:
org.hibernate.cache.EhCacheProvider
u 在部署项目时,需要将调试信息关闭,如关闭显示sql语句、关闭更新数据表、更改日志的输出级别等。