Hibernate二级缓存以及ehcache的搭建配置
前言
这次主要复习Hibernate的二级缓存的相关知识,配置以及使用。二级缓存主要采用第三方的ehcache,也将介绍ehcache缓存的相关配置属性以及在项目中的搭建,具体的项目查看下一篇的 Maven搭建SpringMVC+Hibernate项目详解 的文章。(之前使用过Hibernate的二级缓存,但是没自己搭建和研究过,现在花了半天时间搭建了一下,写下来供大家参考)
1、Hibernate二级缓存
Hibernate包括两个级别的缓存:
1、一级缓存:默认总是启用的session级别的。
2、二级缓存:可选的SessionFactory级别的。
Session级别的以及缓存总是有效的,当应用保持持久化实体、修改持久化实体时,Session并不会吧这种改变flush到数据库,而是缓存在当前Session的一级缓存中,除非程序显示调用session的flush方法,或者查询关闭session时,才会把这先改变一次性的flush到底层数据库,这样可以减少与数据库的交互,从而提高数据库的访问性能。
SessionFactory级别的二级缓存是全局的,应用的所有的Seeion都共享这个二级缓存,当Session需要抓取数据时,Session就会优先从二级缓存中抓取。(主要包括实体缓存,查询缓存)。
2、适用范围
主要适合以下数据放入二级缓存:
1. 很少被修改,大量查询的
2. 不是很重要的数据,允许出现偶尔并发访问的
3、Hibernate二级缓存的配置
Hibernate的二级缓存主要使用第三方缓存插件,这里主要使用Ehcache二级缓存。
首先、我们需要映入ehcache包以及hibernate-ehcache包,maven的pom.xml映入如下:
<!-- hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.3.8.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>4.3.8.Final</version> </dependency> <!-- 二级缓存ehcache --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.9.0</version> </dependency>
其次、我们需要在Hibernate的配置文件中设置二级缓存的相关信息
<!-- 开启二级缓存 ehcache --> <prop key="hibernate.cache.use_second_level_cache">true</prop> <!-- 开启查询的二级缓存 如果不需要就不设置--> <prop key="hibernate.cache.use_query_cache">true</prop> <!-- Hibernate4.0以上设置factory --> <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop> <!-- 二级缓存 ehcache的配置文件位置 --> <prop key="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</prop>
一般Hibernate的二级缓存实体和属性的缓存映射,如果需要将查询数据也二级缓存,需要使用hibernate.cache.use_query_cache开启。
4、Ehcache的配置
ehcache.xml的配置文件如下:
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <diskStore path="java.io.tmpdir/ehcache" /> <!-- DefaultCache setting. --> <defaultCache maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="300" maxElementsOnDisk="1000000" overflowToDisk="true" memoryStoreEvictionPolicy="LRU"> </defaultCache> <!-- Special objects setting. --> <!-- <cache name="org.andy.work.entity.AcctUser" maxElementsInMemory="2" memoryStoreEvictionPolicy="LRU" eternal="true" diskPersistent="false" overflowToDisk="false" maxElementsOnDisk="1000000" /> --> </ehcache>
第一段是配置默认的ehcache二级缓存信息,第二段是特殊的配置(需要配置特殊时)。
4.1、配置详解
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
注:java.io.tmpdir目录为:C:\Users\登录用户\AppData\Local\Temp\(window环境中),所以上面在我的电脑下的目录如下(已经有缓存内容):
当然存储位置我们可以随意的配置如: <diskStore path="D:/ehcache" /> 就是在D盘下的ehcache目录了。
5、配置需二级缓存实体和属性
这里只介绍注解形式的,xml形式的不说了,大多数公司都用注解。
在实体类和实体的那些集合属性上启用二级缓存使用
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
注:如果一个实体需要二级缓存,若该实体含有<set...>,<list...>等属性时,也必须要指定缓存策略。
如下:
package org.andy.work.entity; // Generated 2015-2-3 10:43:00 by Hibernate Tools 4.0.0 import java.util.Date; import java.util.HashSet; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; /** * AcctUser generated by hbm2java */ @Entity @Table(name = "acct_user", catalog = "work") @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public class AcctUser implements java.io.Serializable { /** * */ private static final long serialVersionUID = 6980093847795726310L; private String id; private String nickName; private String telephone; private Date registerTime; private Set<AcctRole> acctRoles = new HashSet<AcctRole>(0); public AcctUser() { } public AcctUser(String id, String nickName) { this.id = id; this.nickName = nickName; } public AcctUser(String id, String nickName, String telephone, Date registerTime, Set<AcctRole> acctRoles) { this.id = id; this.nickName = nickName; this.telephone = telephone; this.registerTime = registerTime; this.acctRoles = acctRoles; } @Id @Column(name = "id", unique = true, nullable = false, length = 36) public String getId() { return this.id; } public void setId(String id) { this.id = id; } @Column(name = "nick_name", nullable = false) public String getNickName() { return this.nickName; } public void setNickName(String nickName) { this.nickName = nickName; } @Column(name = "telephone") public String getTelephone() { return this.telephone; } public void setTelephone(String telephone) { this.telephone = telephone; } @Temporal(TemporalType.TIMESTAMP) @Column(name = "register_time", length = 19) public Date getRegisterTime() { return this.registerTime; } public void setRegisterTime(Date registerTime) { this.registerTime = registerTime; } @JsonIgnoreProperties(value={"acctUsers", "acctAuthorities"}) @ManyToMany(fetch = FetchType.LAZY) @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @JoinTable(name = "acct_user_role", catalog = "work", joinColumns = { @JoinColumn(name = "user_id", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "role_id", nullable = false, updatable = false) }) public Set<AcctRole> getAcctRoles() { return this.acctRoles; } public void setAcctRoles(Set<AcctRole> acctRoles) { this.acctRoles = acctRoles; } }
5.1、缓存usage事务隔离机制
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:
只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离,那么比较适合使用非严格读/写缓存策略。
6、使用查询缓存
查询缓存所缓存的key值就是查询所使用的HQL或SQL语句,需要注意的是:查询缓存不仅要求所使用的HQL语句、SQL语句相同,甚至是要求所传入的参数也相同,Hibernate才能从缓存中查去数据。
查询缓存有如下两步:
1、查询缓存不不仅开启 hibernate.cache.use_query_cache
2、还需要在查询时使用 setCacheable(true)
public List<AcctUser> findAll() { List<AcctUser> acctUsers = this.getCurrentSession().createQuery("from AcctUser").setCacheable(true).list(); return acctUsers; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。