Hibernate ——二级缓存
一、Hibernate 二级缓存
1.Hibernate 二级缓存是 SessionFactory 级别的缓存。
2.二级缓存分为两类:
(1)Hibernate内置二级缓存
(2)外置缓存,可配置的,可插拨的,外置缓存中的数据是数据库数据的复制。
3.二级缓存的并发访问策略
(1)两个并发的事务同时访问持久层的缓存的相同数据时,也有可能出现并发问题。
(2)二级缓存可以设定以下 4 中并发访问策略,每一种对应一种事务隔离级别。
- 非严格读写(Nonstrict-read-write):不保证缓存与数据库中数据的一致性。对应 Read UnCommited 事务隔离级别。
- 读写型(Read-write):提供 Read Commited 级别的事务隔离级别。
- 事务型(Transactional):对应 Repeatable Read 级别的事务隔离级别。
- 只读型(Read-Only):提供 Serializable 级别的数据隔离级别。
4.Hibernate 二级缓存是进程或集群范围内的缓存。是可配置的的插件。这里以 Ehcache 为例。不支持事务型的并发访问策略。
5.配置 Ehcache
(1)添加 Jar 包

(2)在 Hibernate 配置文件中启用二级缓存并指定适配的缓存适配器。
在 <session-factory> 元素内添加:
<property name="cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
(3)在 Hibernate 配置文件中配置需要使用二级缓存的持久化类,并设置它的二级缓存的并发访问策略。如:
<class-cache class="com.solverpeng.hql.Department" usage="read-write"/>
需要注意的是:<session-factory> 元素内子元素的顺序:property*, mapping*, (class-cache|collection-cache)*, event*, listener*,class-cache 元素必须位于 mapping 节点后。
(4)或者也可以在 hbm 文件中配置,如:
<hibernate-mapping>
<class name="com.solverpeng.hql.Employee" table="employee" schema="hibernate">
<cache usage="read-write"/>
<id name="empId" column="emp_id"/>
<property name="empName" column="emp_name"/>
<property name="salary" column="salary"/>
<many-to-one name="dept" class="com.solverpeng.hql.Department">
<column name="dept_id_fk" not-null="true"/>
</many-to-one>
</class>
</hibernate-mapping>
6. 测试 Hibernate 二级缓存
(1)查询单个对象缓存
@Test
public void testSecondCache() {
Employee o = (Employee) session.get(Employee.class, 6);
System.out.println(o); transaction.commit();
session.close();
session = factory.openSession();
transaction = session.beginTransaction(); Employee o1 = (Employee) session.get(Employee.class, 6);
System.out.println(o1);
}
查询同一个对象两次,中间关闭 Session 再开启。
没有配置二级缓存:
Hibernate:
select
employee0_.emp_id as emp1_1_0_,
employee0_.emp_name as emp2_1_0_,
employee0_.salary as salary3_1_0_,
employee0_.dept_id_fk as dept4_1_0_
from
hibernate.employee employee0_
where
employee0_.emp_id=?
com.solverpeng.hql.Employee@40dd58f3
Hibernate:
select
employee0_.emp_id as emp1_1_0_,
employee0_.emp_name as emp2_1_0_,
employee0_.salary as salary3_1_0_,
employee0_.dept_id_fk as dept4_1_0_
from
hibernate.employee employee0_
where
employee0_.emp_id=?
com.solverpeng.hql.Employee@40dd58f3
结果:
发送了2条 SQL 语句。
配置二级缓存后(可以在Hibernate 配置文件中配置,也可以在 Employee hbm 配置文件中配置):
Hibernate:
select
employee0_.emp_id as emp1_1_0_,
employee0_.emp_name as emp2_1_0_,
employee0_.salary as salary3_1_0_,
employee0_.dept_id_fk as dept4_1_0_
from
hibernate.employee employee0_
where
employee0_.emp_id=?
com.solverpeng.hql.Employee@40dd58f3
com.solverpeng.hql.Employee@40dd58f3
结果:
只发送了1条 SQL 语句。
(2)集合缓存
@Test
public void testCollectionSecondLevelCache() {
Department department = (Department) session.get(Department.class, 6);
System.out.println(department.getDeptName());
System.out.println(department.getEmps().size()); transaction.commit();
session.close();
session = factory.openSession();
transaction = session.beginTransaction(); Department department2 = (Department) session.get(Department.class, 6);
System.out.println(department2.getDeptName());
System.out.println(department2.getEmps().size()); }
在没有配置二级缓存的情况下:
Hibernate:
select
department0_.dept_id as dept1_0_0_,
department0_.dept_name as dept2_0_0_
from
hibernate.department department0_
where
department0_.dept_id=?
dept-aa
Hibernate:
select
emps0_.dept_id_fk as dept4_0_1_,
emps0_.emp_id as emp1_1_1_,
emps0_.emp_id as emp1_1_0_,
emps0_.emp_name as emp2_1_0_,
emps0_.salary as salary3_1_0_,
emps0_.dept_id_fk as dept4_1_0_
from
hibernate.employee emps0_
where
emps0_.dept_id_fk=?
3
Hibernate:
select
department0_.dept_id as dept1_0_0_,
department0_.dept_name as dept2_0_0_
from
hibernate.department department0_
where
department0_.dept_id=?
dept-aa
Hibernate:
select
emps0_.dept_id_fk as dept4_0_1_,
emps0_.emp_id as emp1_1_1_,
emps0_.emp_id as emp1_1_0_,
emps0_.emp_name as emp2_1_0_,
emps0_.salary as salary3_1_0_,
emps0_.dept_id_fk as dept4_1_0_
from
hibernate.employee emps0_
where
emps0_.dept_id_fk=?
3
结果:
查询了两次 Department,两次Employee
只配置 Department 二级缓存:
<class-cache class="com.solverpeng.hql.Department" usage="read-write"/>
Hibernate:
select
department0_.dept_id as dept1_0_0_,
department0_.dept_name as dept2_0_0_
from
hibernate.department department0_
where
department0_.dept_id=?
dept-aa
Hibernate:
select
emps0_.dept_id_fk as dept4_0_1_,
emps0_.emp_id as emp1_1_1_,
emps0_.emp_id as emp1_1_0_,
emps0_.emp_name as emp2_1_0_,
emps0_.salary as salary3_1_0_,
emps0_.dept_id_fk as dept4_1_0_
from
hibernate.employee emps0_
where
emps0_.dept_id_fk=?
3
dept-aa
Hibernate:
select
emps0_.dept_id_fk as dept4_0_1_,
emps0_.emp_id as emp1_1_1_,
emps0_.emp_id as emp1_1_0_,
emps0_.emp_name as emp2_1_0_,
emps0_.salary as salary3_1_0_,
emps0_.dept_id_fk as dept4_1_0_
from
hibernate.employee emps0_
where
emps0_.dept_id_fk=?
3
结果:
只查询了一次 Department,2次Employee。
说明:
开启 Department 二级缓存后,会对 Department 进行缓存,而与其关联的 emps 不会进行缓存。
配置 Department 二级缓存,同时配置关联的 emps 缓存。
<class-cache class="com.solverpeng.hql.Department" usage="read-write"/>
<collection-cache collection="com.solverpeng.hql.Department.emps" usage="read-write"/>
Hibernate:
select
department0_.dept_id as dept1_0_0_,
department0_.dept_name as dept2_0_0_
from
hibernate.department department0_
where
department0_.dept_id=?
dept-aa
Hibernate:
select
emps0_.dept_id_fk as dept4_0_1_,
emps0_.emp_id as emp1_1_1_,
emps0_.emp_id as emp1_1_0_,
emps0_.emp_name as emp2_1_0_,
emps0_.salary as salary3_1_0_,
emps0_.dept_id_fk as dept4_1_0_
from
hibernate.employee emps0_
where
emps0_.dept_id_fk=?
3
-----------------------------
dept-aa
Hibernate:
select
employee0_.emp_id as emp1_1_0_,
employee0_.emp_name as emp2_1_0_,
employee0_.salary as salary3_1_0_,
employee0_.dept_id_fk as dept4_1_0_
from
hibernate.employee employee0_
where
employee0_.emp_id=?
Hibernate:
select
employee0_.emp_id as emp1_1_0_,
employee0_.emp_name as emp2_1_0_,
employee0_.salary as salary3_1_0_,
employee0_.dept_id_fk as dept4_1_0_
from
hibernate.employee employee0_
where
employee0_.emp_id=?
Hibernate:
select
employee0_.emp_id as emp1_1_0_,
employee0_.emp_name as emp2_1_0_,
employee0_.salary as salary3_1_0_,
employee0_.dept_id_fk as dept4_1_0_
from
hibernate.employee employee0_
where
employee0_.emp_id=?
3
结果:
发送了更多的查询 Employee 的SQL。
说明:
开启集合的二级缓存后,此时会缓存集合中对象的 id ,而不会对集合中的对象进行缓存。若想缓存,需要关联的集合中的对象也开启二级缓存。如:
<class-cache class="com.solverpeng.hql.Department" usage="read-write"/>
<collection-cache collection="com.solverpeng.hql.Department.emps" usage="read-write"/>
<class-cache class="com.solverpeng.hql.Employee" usage="read-write"/>
Hibernate:
select
department0_.dept_id as dept1_0_0_,
department0_.dept_name as dept2_0_0_
from
hibernate.department department0_
where
department0_.dept_id=?
dept-aa
Hibernate:
select
emps0_.dept_id_fk as dept4_0_1_,
emps0_.emp_id as emp1_1_1_,
emps0_.emp_id as emp1_1_0_,
emps0_.emp_name as emp2_1_0_,
emps0_.salary as salary3_1_0_,
emps0_.dept_id_fk as dept4_1_0_
from
hibernate.employee emps0_
where
emps0_.dept_id_fk=?
3
-----------------------------
dept-aa
3
结果:
除 Department 外,关联的 Employee 也被缓存了。
(3)查询缓存(针对 HQL、QBC)
在二级缓存开启的情况下,HQL、QBC 也不能对查询进行缓存。
@Test
public void testQueryCache() {
Query query = session.createQuery("from Employee "); List<Employee> list = query.list();
System.out.println(list.size()); List<Employee> emps2 = query.list();
System.out.println(emps2.size());
}
Hibernate:
select
employee0_.emp_id as emp1_1_,
employee0_.emp_name as emp2_1_,
employee0_.salary as salary3_1_,
employee0_.dept_id_fk as dept4_1_
from
hibernate.employee employee0_
12
Hibernate:
select
employee0_.emp_id as emp1_1_,
employee0_.emp_name as emp2_1_,
employee0_.salary as salary3_1_,
employee0_.dept_id_fk as dept4_1_
from
hibernate.employee employee0_
12
开启查询缓存:
- 在 Hibernate 配置文件中开启查询缓存
- 若想启用查询缓存的查询语句,需要调用 Query 或 Criteria 的 setCacheable() 方法。
- 查询缓存依赖于二级缓存
<property name="hibernate.cache.use_query_cache">true</property>
@Test
public void testQueryCache() {
Query query = session.createQuery("from Employee ");
query.setCacheable(true);
List<Employee> list = query.list();
System.out.println(list.size()); List<Employee> emps2 = query.list();
System.out.println(emps2.size());
}
Hibernate:
select
employee0_.emp_id as emp1_1_,
employee0_.emp_name as emp2_1_,
employee0_.salary as salary3_1_,
employee0_.dept_id_fk as dept4_1_
from
hibernate.employee employee0_
12
12
(4)时间戳缓存区域:时间戳缓存区存放了对于查询结果相关的表进行插入、更新或删除操作的时间戳。Hibernate通过时间戳缓存区来判定被缓存的查询结果是否过期。
@Test
public void testTimStampCache() {
Query query = session.createQuery("from Employee ");
query.setCacheable(true);
List<Employee> list = query.list();
System.out.println(list.size()); Employee employee = (Employee) session.get(Employee.class, 6);
employee.setEmpName("emp@@"); List<Employee> emps2 = query.list();
System.out.println(emps2.size());
}
Hibernate:
select
employee0_.emp_id as emp1_1_,
employee0_.emp_name as emp2_1_,
employee0_.salary as salary3_1_,
employee0_.dept_id_fk as dept4_1_
from
hibernate.employee employee0_
12
Hibernate:
update
hibernate.employee
set
emp_name=?,
salary=?,
dept_id_fk=?
where
emp_id=?
Hibernate:
select
employee0_.emp_id as emp1_1_,
employee0_.emp_name as emp2_1_,
employee0_.salary as salary3_1_,
employee0_.dept_id_fk as dept4_1_
from
hibernate.employee employee0_
12
二、ehcache.xml
<ehcache>
<diskStore path="java.io.tmpdir"/> <defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/> <cache name="sampleCache1"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/> <cache name="sampleCache2"
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/> </ehcache>
1.<diskStore>: 指定一个目录:当 EHCache 把数据写到硬盘上时, 将把数据写到这个目录下.
2.<defaultCache>: 设置缓存的默认数据过期策略
3.<cache> 设定具体的命名缓存的数据过期策略。每个命名缓存代表一个缓存区域
4.缓存区域(region):一个具有名称的缓存块,可以给每一个缓存块设置不同的缓存策略。如果没有设置任何的缓存区域,则所有被缓存的对象,都将使用默认的缓存策略。即:<defaultCache.../>
5.Hibernate在不同的缓存区域保存不同的类/集合。
- 对于类而言,区域的名称是类名。如:com.atguigu.domain.Customer
- 对于集合而言,区域的名称是类名加属性名。如com.atguigu.domain.Customer.orders
6.cache 元素的属性
(1)name:设置缓存的名字,它的取值为类的全限定名或类的集合的名字
(2)maxInMemory:设置基于内存的缓存中可存放的对象最大数目
(3)eternal:设置对象是否为永久的,true表示永不过期,此时将忽略timeToIdleSeconds 和 timeToLiveSeconds属性; 默认值是false。
(4)timeToIdleSeconds:设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。当对象过期时,EHCache会把它从缓存中清除。如果此值为0,表示对象可以无限期地处于空闲状态。
(5)timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。如果此值为0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值。
(6)overflowToDisk:设置基于内存的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中。
三、管理 Session
–Session 对象的生命周期与本地线程绑定
–Session 对象的生命周期与 JTA 事务绑定
–Hibernate 委托程序管理 Session 对象的生命周期
四、批量处理数据
建议通过 JDBC 的方式来进行批量操作。
@Test
public void testBathch() {
session.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
// 执行批量操作
}
});
}
五、总结
配置 Hibernate 二级缓存的步骤:
1.配置 Hibernate 配置文件
(1)配置启用二级缓存
<property name="cache.use_second_level_cache">true</property>
(2)配置二级缓存使用的产品
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
(3)配置对哪些类使用 hibernate 的二级缓存以及并发策略
<class-cache class="com.solverpeng.hql.Department" usage="read-write"/>
<collection-cache collection="com.solverpeng.hql.Department.emps" usage="read-write"/>
<class-cache class="com.solverpeng.hql.Employee" usage="read-write"/>
(4)在 hbm 文件中配置缓存
<set name="emps" inverse="true">
<cache usage="read-write"/>
<key>
<column name="dept_id_fk" not-null="true"/>
</key>
<one-to-many not-found="ignore" class="com.solverpeng.hql.Employee"/>
</set>
2. 对于集合缓存来说,还需要配置集合中的元素对应的持久化类也使用二级缓存! 否则将会多出 n 条 SQL 语句.
3. 查询缓存
(1)在 Hibernate 配置文件中开启查询缓存支持:<property name="cache.use_query_cache">true</property>
(2)调用 Query 或 Criteria 的 setCacheable(true)方法
(3)查询缓存依赖于二级缓存
Hibernate ——二级缓存的更多相关文章
- 配置Hibernate二级缓存时,不能初始化RegionFactory的解决办法
配置Hibernate 二级缓存时,出现以下bug提示: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder&quo ...
- 配置Hibernate二级缓存步骤
配置Hibernate二级缓存步骤: 加入二级缓存的jar包及配置文件 jar包位置:hibernate-release-4.1.8.Final\lib\optional\ehcache下所有jar包 ...
- Hibernate 二级缓存 总结整理(转)
和<Hibernate 关系映射 收集.总结整理> 一样,本篇文章也是我很早之前收集.总结整理的,在此也发上来 希望对大家有用.因为是很早之前写的,不当之处请指正. 1.缓存:缓存是什么, ...
- Hibernate(十六):Hibernate二级缓存
Hibernate缓存 缓存(Cache):计算机领域非常通用的概念.它介于应用程序和永久性数据存储源(如磁盘上的文件或者数据库)之间,起作用是降低应用程序直接读取永久性数据存储源的频率,从而提高应用 ...
- hibernate二级缓存demo2
@Test public void hello3(){ Session session=sessionFactory.openSession(); List list = session.create ...
- hibernate二级缓存整合
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http:// ...
- ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存
ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存 hibernate : Hibernate是一个持久层框架,经常访问物理数据库 ...
- spring boot集成ehcache 2.x 用于hibernate二级缓存
https://www.jianshu.com/p/87b2c309b776 本文将介绍如何在spring boot中集成ehcache作为hibernate的二级缓存.各个框架版本如下 spring ...
- js相关(easyUI),触发器,ant,jbpm,hibernate二级缓存ehcache,Javamail,Lucene,jqplot,WebService,regex,struts2,oracle表空间
*********************************************js相关********************************************* // 在指 ...
随机推荐
- MVC Castle依赖注入实现代码
1.MVc 实现依赖注入 public class WindsorControllerFactory : DefaultControllerFactory { private readonly IKe ...
- 译文---C#堆VS栈(Part One)
前言 本文主要是讲解C#语言在内存中堆.栈的使用情况,使读者能更好的理解值类型.引用类型以及线程栈.托管堆. 首先感谢原文作者:Matthew Cochran 为我们带来了一篇非常好的文章,并配以大量 ...
- 为什么google bazel构建工具流行不起来
作者Jack47 转载请保留作者和原文出处 之前博主写了系列文章Google软件构建工具Bazel原理及使用方法介绍.最近使用了一段时间后,觉得这个东西不是一种通用的构建工具,很难对接到情况复杂的大的 ...
- MySQL mysqldump数据导出详解
介绍 在日常维护工作当中经常会需要对数据进行导出操作,而mysqldump是导出数据过程中使用非常频繁的一个工具:它自带的功能参数非常多,文章中会列举出一些常用的操作,在文章末尾会将所有的参数详细说明 ...
- MySQL 忘记root密码解决办法
标签:root密码不为空 概述 很多时候mysql安装完root用户的默认密码不为空,这时候就需要通过其它办法登入到mysql重置密码. 步骤 方法1:查看/root/.mysql_secret文件 ...
- [ASP.NET MVC 小牛之路]10 - Controller 和 Action (2)
继上一篇文章之后,本文将介绍 Controller 和 Action 的一些较高级特性,包括 Controller Factory.Action Invoker 和异步 Controller 等内容. ...
- DLL导出函数和类的定义区别 __declspec(dllexport)
DLL导出函数和类的定义区别 __declspec(dllexport) 是有区别的, 请看 : //定义头文件的使用方,是导出还是导入 #if defined(_DLL_API) #ifndef D ...
- Directive间的通信
Directive间的通信 源自大漠的<AngularJS>5个实例详解Directive(指令)机制 这个例子主要的难点在于如何在子Expander里面访问外层Accordion的sco ...
- Java集合类的组织结构和继承、实现关系
Collection继承.实现关系如下(说明(I)表示接口,(C)表示Java类,<--表示继承,<<--表示实现): (I)Iterable |<--(I)Collectio ...
- 服务器.htaccess 详解以及 .htaccess 参数说明(转载)
htaccess文件(或者”分布式配置文件”)提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录.作为用户,所能使用的命令受到限 ...