一级缓存:
会话session、事务级别的,事务退出,缓存就失效了。
实体管理器在事务执行期间持有一份数据的拷贝,而非直接操作数据源。
二级缓存:
进程范围级或集群范围的缓存,这个级别的缓存可配置和修改,整个应用程序的生命周期内都可以访问。
由于多个事务会同时访问二级缓存中相同的数据,因此二级缓存必须提供必要的并发访问策略
以id为标识放到缓存(针对id)
访问过程:先一级缓存、后二级缓存,再数据源
桥接第三方缓存,hibernate二级缓存的实现:
1.ehcache
2.OScache
3.JBossCache
4.Memcached
......
什么样的数据适合二级缓存呢?
1.很少被修改的数据
2.不是很重要,允许偶尔出现并发的数据
3.不会被高并发访问的数据
4.参数数据,通常是数量有限,极少被修改,大量的被其它实例引用的
不适合使用二级缓存?
1.经常被修改的数据,代价太大,得不偿失
2.金钱敏感的数据,绝对不允许出现并发
3.与其他应用共享的数据
查询缓存:
批量的缓存、批量的获取,如按查询条件、查询结果进行缓存;
JPA+Ehcache缓存配置:
1.加入Ehcache依赖
<!--Ehcache-core 包 --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>2.6.9</version> </dependency> <!--添加Hibernate-Ehcache包 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>${hibernate-version}</version> </dependency>
2.配置ehcache.xml
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"> <diskStore path="java.io.tmpdir/ehcache"/> <!-- 默认缓存 --> <defaultCache maxElementsInMemory="1000" <!-- 默认缓存中存最多数据项目 --> eternal="false" <!--是否永不过期--> timeToIdleSeconds="120" <!--空闲多长时间后从缓存中删除--> timeToLiveSeconds="120" <!--活跃多长时间后从缓存中删除--> overflowToDisk="false"/><!--超过maxElementsInMemory之后是否存储到硬盘--> <!-- 题目缓存--> <cache name="questionCache" maxElementsInMemory="1000" eternal="true" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" memoryStoreEvictionPolicy="LRU" <!--数据项失效策略--> /> </ehcache>
3.persistence.xml配置加入缓存配置
entry key="hibernate.cache.use_second_level_cache" value="false" /><!--开启二级缓存-->
<entry key="hibernate.cache.use_query_cache" value="false" /><!--开启查询缓存-->
<entry key="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider"/> <!--ehcache支持-->
<entry key="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" /><!--ehcache支持-->
<entry key="hibernate.cache.provider_configuration" value="classpath:ehcache.xml"/><!--ehcache详细配置-->
4.配置需二级缓存实体和属性
在实体类和实体的那些集合属性上启用二级缓存使用
@Entity @Table(name = "user") @Cache(usage = CacheConcurrencyStrategy.READ_WRITE,region="指定的cache") @Cacheable(true) public class User implements java.io.Serializable { private static final long serialVersionUID = 6980093847795726310L; private String id; private String userName; private String password; private Set<Role> roles = new HashSet<Role>(); ....省略 /** *注:如果一个实体需要二级缓存,若该实体含有<set...>,<list...>等属性时,也必须要指定缓存策略。 */ @ManyToMany(fetch = FetchType.LAZY) @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @JoinTable(name = "user_role", joinColumns = { @JoinColumn(name = "user_id", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "role_id", nullable = false, updatable = false) }) public Set<Role> getRoles() { return this.roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } }
Usage提供缓存对象的事务隔离机制有如下几种:
(NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)
ehcache不支持transaction事务机制,但其他三种可以使用:
read-only::
无需修改, 那么就可以对其进行只读 缓存,注意,在此策略下,如果直接修改数据库,即使能够看到前台显示效果,
但是将对象修改至cache中会报error,cache不会发生作用。另:删除记录会报错,因为不能在read-only模式的对象从cache中删除。
read-write:
需要更新数据,那么使用读/写缓存 比较合适,前提:数据库不可以为serializable transaction isolation level(序列化事务隔离级别)
nonstrice-read-write:
只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离,那么比较适合使用非严格读/写缓存策略。
5.配置查询缓存
a.通过添加@QueryHints来实现查询缓存
public interface DictDao extends JpaRepository<Dict, Integer>,JpaSpecificationExecutor<Dict>{ // spring-data-jpa默认继承实现的一些方法,实现类为SimpleJpaRepository。 // 该类中的方法不能通过@QueryHint来实现查询缓存。 @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value ="true") }) List<Dict> findAll(); @Query("from Dict") @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value ="true") }) List<Dict> findAllCached(); @Query("select t from Dict t where t.name = ?1") @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value ="true") }) Dict findDictByName(String name); }
b.自定义Repository扩展接口内使用查询缓存
public class UserReposiotryImpl { @PersistenceContext private EntityManager em; /** * 使用查询缓存,调用setHint方法配置. */ public User findByCustomizeId() { return (User) em.createQuery("from User p where p.id=1") .setHint("org.hibernate.cacheable", true).getSingleResult(); }
<!-- 默认缓存 --> <defaultCache maxElementsInMemory="1000" <!-- 默认缓存中存最多数据项目 --> eternal="false" <!--是否永不过期--> timeToIdleSeconds="120" <!--空闲多长时间后从缓存中删除--> timeToLiveSeconds="120" <!--活跃多长时间后从缓存中删除--> overflowToDisk="false"/><!--超过maxElementsInMemory之后是否存储到硬盘--> <!-- 题目缓存--> <cache name="questionCache" maxElementsInMemory="1000" eternal="true" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false" memoryStoreEvictionPolicy="LRU" <!--数据项失效策略--> /> </ehcache>
3.persistence.xml配置加入缓存配置
entry key="hibernate.cache.use_second_level_cache" value="false" /><!--开启二级缓存-->
<entry key="hibernate.cache.use_query_cache" value="false" /><!--开启查询缓存-->
<entry key="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider"/> <!--ehcache支持-->
<entry key="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" /><!--ehcache支持-->
<entry key="hibernate.cache.provider_configuration" value="classpath:ehcache.xml"/><!--ehcache详细配置-->
4.配置需二级缓存实体和属性
在实体类和实体的那些集合属性上启用二级缓存使用
@Entity @Table(name = "user") @Cache(usage = CacheConcurrencyStrategy.READ_WRITE,region="指定的cache") @Cacheable(true) public class User implements java.io.Serializable { private static final long serialVersionUID = 6980093847795726310L; private String id; private String userName; private String password; private Set<Role> roles = new HashSet<Role>(); ....省略 /** *注:如果一个实体需要二级缓存,若该实体含有<set...>,<list...>等属性时,也必须要指定缓存策略。 */ @ManyToMany(fetch = FetchType.LAZY) @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @JoinTable(name = "user_role", joinColumns = { @JoinColumn(name = "user_id", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "role_id", nullable = false, updatable = false) }) public Set<Role> getRoles() { return this.roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } }
Usage提供缓存对象的事务隔离机制有如下几种:
(NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)
ehcache不支持transaction事务机制,但其他三种可以使用:
read-only::
无需修改, 那么就可以对其进行只读 缓存,注意,在此策略下,如果直接修改数据库,即使能够看到前台显示效果,
但是将对象修改至cache中会报error,cache不会发生作用。另:删除记录会报错,因为不能在read-only模式的对象从cache中删除。
read-write:
需要更新数据,那么使用读/写缓存 比较合适,前提:数据库不可以为serializable transaction isolation level(序列化事务隔离级别)
nonstrice-read-write:
只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离,那么比较适合使用非严格读/写缓存策略。
5.配置查询缓存
a.通过添加@QueryHints来实现查询缓存
public interface DictDao extends JpaRepository<Dict, Integer>,JpaSpecificationExecutor<Dict>{ // spring-data-jpa默认继承实现的一些方法,实现类为SimpleJpaRepository。 // 该类中的方法不能通过@QueryHint来实现查询缓存。 @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value ="true") }) List<Dict> findAll(); @Query("from Dict") @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value ="true") }) List<Dict> findAllCached(); @Query("select t from Dict t where t.name = ?1") @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value ="true") }) Dict findDictByName(String name); }
b.自定义Repository扩展接口内使用查询缓存
public class UserReposiotryImpl { @PersistenceContext private EntityManager em; /** * 使用查询缓存,调用setHint方法配置. */ public User findByCustomizeId() { return (User) em.createQuery("from User p where p.id=1") .setHint("org.hibernate.cacheable", true).getSingleResult(); }