一、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 ——二级缓存的更多相关文章

  1. 配置Hibernate二级缓存时,不能初始化RegionFactory的解决办法

    配置Hibernate 二级缓存时,出现以下bug提示: SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder&quo ...

  2. 配置Hibernate二级缓存步骤

    配置Hibernate二级缓存步骤: 加入二级缓存的jar包及配置文件 jar包位置:hibernate-release-4.1.8.Final\lib\optional\ehcache下所有jar包 ...

  3. Hibernate 二级缓存 总结整理(转)

    和<Hibernate 关系映射 收集.总结整理> 一样,本篇文章也是我很早之前收集.总结整理的,在此也发上来 希望对大家有用.因为是很早之前写的,不当之处请指正. 1.缓存:缓存是什么, ...

  4. Hibernate(十六):Hibernate二级缓存

    Hibernate缓存 缓存(Cache):计算机领域非常通用的概念.它介于应用程序和永久性数据存储源(如磁盘上的文件或者数据库)之间,起作用是降低应用程序直接读取永久性数据存储源的频率,从而提高应用 ...

  5. hibernate二级缓存demo2

    @Test public void hello3(){ Session session=sessionFactory.openSession(); List list = session.create ...

  6. hibernate二级缓存整合

    <?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http:// ...

  7. ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存

    ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存 hibernate  : Hibernate是一个持久层框架,经常访问物理数据库 ...

  8. spring boot集成ehcache 2.x 用于hibernate二级缓存

    https://www.jianshu.com/p/87b2c309b776 本文将介绍如何在spring boot中集成ehcache作为hibernate的二级缓存.各个框架版本如下 spring ...

  9. js相关(easyUI),触发器,ant,jbpm,hibernate二级缓存ehcache,Javamail,Lucene,jqplot,WebService,regex,struts2,oracle表空间

    *********************************************js相关********************************************* // 在指 ...

随机推荐

  1. PHP基础知识之foreach

    定义: foreach (array_expression as $value)------------循环时传递key foreach (array_expression as $key => ...

  2. 关于Java8函数式编程你需要了解的几点

    函数式编程与面向对象的设计方法在思路和手段上都各有千秋,在这里,我将简要介绍一下函数式编程与面向对象相比的一些特点和差异. 函数作为一等公民 在理解函数作为一等公民这句话时,让我们先来看一下一种非常常 ...

  3. serialVersionUID, ObjectInputStream与ObjectOutputStream类,Serializable接口,serialVersionUID的作用和用法

    ObjectInputStream与ObjectOutputStream类所读写的对象必须实现Serializable接口,对象中的transient和static类型成员变量不会被读取和写入 Ser ...

  4. 解决 PowerDesigner 错误 The generation has been cancelled…

    在Model Settings中按照如下图设置即可.

  5. Wishart distribution

    Introduction In statistics, the Wishart distribution is generalization to multiple dimensions of the ...

  6. io.js入门(二)—— 所支持的ES6(上)

    io.js的官网上有专门介绍其所支持的ES6特性的页面(点我查看),上面介绍到,相比nodeJS,io.js已从根本上支持了新版V8引擎上所支持的ES6特性,无需再添加任何运行时标志(如 --harm ...

  7. Mongodb 学习笔记

    Mongo DB NoSql简介 MongoDB简介 在Windows平台下安装Mongo Mongo DB官方文档 MongoDB基本命令 MongoDB的默认安装路径为 C:\Program Fi ...

  8. 【VC++技术杂谈002】打印技术之获取及设置系统默认打印机

    本文主要介绍如何获取以及设置系统的默认打印机. 1.获取系统中的所有打印机 获取系统中的所有打印机可以使用EnumPrinters()函数,该函数可以枚举全部的本地.网络打印机信息.其函数原型为: B ...

  9. Worktile协同特色之一:无处不在的关注

    团队沟通中常见问题 在回答这个问题之前,我们不妨先来思考一下,团队成员之间互相配合沟通的几个问题:1. 任务的执行者在完成这个任务时,如何通知到此任务相关联的其他成员,比如该任务的后续任务执行者?2. ...

  10. EF6 Power Tools的妙用和问题

    环境:vs2013+EF:6.1.3.0+Power Tools:Beta 4 power tools:是一个反向工程,在已有数据库的情况下,可以利用它生成Code Frist模式的代码. 问题: 它 ...