缓存,介于应用程序和永久数据存储源之间,作用是为了降低应用程序对物理数据源访问的频率,从而提高应用的运行性能。

例如我们cpu执行效率每秒处理的数据高达上千兆,而我们的硬盘读取速度却没那么高,读取几百兆,这时候我们使用缓存来存储数据,存储满后一次性交由cpu处理。

Hibernate中的缓存,同样是为了提高效率。Hibernate的缓存包括Session的缓存和SessionFactory的缓存。

Session的缓存是内置的,不能被卸载,也被称为Hibertnate的一级缓存。

SessionFactory有一个内置缓存和外置缓存。SessionFactory的外置缓存是一个可配置的缓存插件。默认情况下,Hibernate不会启用这个缓存插件。被称为Hibernate的二级缓存。

缓存的范围

缓存的范围决定了缓存的生命周期以及可以被谁访问。

事务范围:缓存只能被当前事务访问。一级缓存是Session的缓存,Session对象生命周期通常对应一个事务,因此是事务范围的缓存。

进程范围:缓存被进程内的所有事务共享。二级缓存是可配置的缓存插件,由SessionFactory管理,SessionFactory生命周期和应用程序的进程对应,因此是进程范围的缓存。

集群范围:在集群环境中,缓存被同一个机器或者多个机器上的多个进程共享。

Hibernate一级缓存:Session缓存

Session缓存是Hibernate的一级缓存。Session对象中具有一个缓存。Session的缓存是一块内存空间,存放的是持久化对象。
当Session通过save方法持久化一个对象时,该对象被加入到Session缓存中。
当Session通过get方法获取一个持久化对象时,Session会先判断Session缓存中是否存在这个对象,如果存在,就不需要再从数据库中查找。

我们来测试一下缓存的存在:

     //开启事务
Transaction ts=session.beginTransaction();
//加上断点,当我们执行完这一步,会打印select语句,而后面的都不会打印,说明并没有从数据库中获取
User user1=session.get(User.class, 5);
//这次get方法会先从session缓存中查找,由于已经存在,直接返回引用
User user2=session.get(User.class, 5);
User user3=session.get(User.class, 5);
System.out.println(user1==user2);//true
System.out.println(user1==user3);//true
session.close();

脏检查及清理缓存的机制

我们先来看下面的例子

     Transaction ts=session.beginTransaction();
User user1=session.get(User.class, 5);
user1.setName("swaggy");
ts.commit();

我们发现我们改变了Name属性,这时候session缓存中的对象的name属性和数据库表中的NAME字段不一致了。但是我们并没有进行更新操作,而是直接提交了事务。
幸运的是,Session中在清理缓存的时候,会自动进行脏检查。如果发现Session缓存中的持久化对象和数据库中的记录不一致,就会根据对象的最新属性去更新数据库。
所以在本例中,Session会自动提交一个update语句对数据库进行更新。

Session是怎样进行脏检查的呢?

当一个对象被加入到Sesion缓存中时,Session会为该对象复制一份快照。当Session清理缓存时,会比较当前对象的属性和快照来判断是否发生变化,如果发生变化,就会根据最新属性来执行相关的更新操作。

我们看下面一个例子加深对快照的理解

        //我们从数据库中取出 id为5,name为tom,password为123456的对象
Transaction ts=session.beginTransaction();
User user1=session.get(User.class, 5);
session.update(user1);
session.close();
过程:获取了持久化对象,放入缓存中,并创建了快照,我们执行更新,Session缓存中的对象会和快照进行比较,没有任何变化,所以不会执行update语句。
        //我们自己设置一个和数据库中一模一样的对象,这时候会打印update语句
Transaction ts=session.beginTransaction();
User user=new User();
user.setId(5);
user.setName("tom");
user.setPassword("123456");
session.update(user);
ts.commit();
session.close();

过程:因为此时我们执行update语句时会将对象直接放入缓存中,但是没有持久化对象的快照,所以进行对比结果就是不一致,所以尽管什么都没更改,还是会执行update语句,在控制台打印。

什么时候会清理缓存呢?

  • -默认情况下,在调用commit()方法时会先清理缓存。再向数据库提交事务。
  • -当执行查询操作时,如果缓存中的持久化对象属性已经发生了改变,就会先清理缓存,同步数据,保证查询到的是正确的结果。
  • -当应用程序显式调用Session的flush()方法时
  • -Session清理缓存的例外情况,如果对象使用的是native生成策略生成OID,那么调用Session的save()方法来保存该对象时,会立刻执行向数据库的插入语句。

如果不希望Session在以上默认的时间点清理缓存,可以通过Session的setFlushMode()方法来设定清理缓存的时间点。
FlushMode类定义了三种清理模式。

                            各种查询方法          commit()方法        flush()方法
-FlushMode.AUTO(默认模式) 清理 清理 清理
-FlushMode.COMMIT 不清理 清理 清理
-FlushMode.NEVER 不清理 不清理 清理 例如Session.setFlushMode(FlushMode.AUTO)

Hibernate的二级缓存:SessionFactory

二级缓存简介

二级缓存是一个可插拔的缓存插件,由SessionFactory管理,是进程范围的缓存。
二级缓存有可能出现并发问题,因此需要采用适当的并发访问策略。
该策略为缓存中的数据提供了事务隔离级别。
Hibernate还提供了查询缓存,依赖于二级缓存。

二级缓存中存放什么?

符合以下条件的数据适合存放在二级缓存中

  • -很少被修改的数据
  • -不是很重要的数据,允许偶然出现的并发问题
  • -参考数据(指供应用程序参考的常量数据)

以下数据不适合存放到二级缓存中

  • -经常被修改的数据
  • -财务数据,绝对不允许出现并发文日
  • -与其他应用共享的数据

二级缓存中缓存的并不是对象,而是对象的散装数据。

常用二级缓存插件

二级缓存是可配置的插件,Hibernate允许选用以下的缓存插件

  • -EHCache:可作为进程范围内的缓存。存放数据的物理介质可以是硬盘或者内存,支持hibernate的查询缓存。
  • -OSCache:可作为进程范围内的缓存,存放数据的物理介质可以是硬盘或者内存,支持hibernate的查询缓存,提供了丰富的缓存数据过期策略。
  • -SwarmCache:可作为集群范围内的缓存,不支持Hibernate的查询缓存。
  • -JBossCache:可作为集群范围内的缓存,支持事务并发访问策略。支持Hibernate的查询缓存。

二级缓存的事务隔离级别

    transactional(事务型):
仅在受管理的环境中适用
提供Repeatable Read事务隔离级别
适用经常被读,很少修改的数据
可以防止脏读和不可重复读的并发问题
缓存支持事务,发生异常的时候,缓存也能够回滚
read-write(读写型);
提供Read Committed事务隔离级别
在非集群的环境中适用
适用经常被读,很少修改的数据
可以防止脏读
更新缓存的时候会锁定缓存中的数据
nonstrict-read-write(非严格读写型):
适用极少被修改,偶尔允许脏读的数据(两个事务同时修改数据的情况很少见)
不保证缓存和数据库中数据的一致性
为缓存数据设置很短的过期时间,从而尽量避免脏读
不锁定缓存中的数据
read-only(只读型):
适用从来不会被修改的数据(如参考数据)
在此模式下,如果对数据进行更新操作,会有异常
事务隔离级别低,并发性能高
在集群环境中也能完美运作

为了把这些第三方缓存插件集成到Hibernate中,Hibernate提供了org.hibernate.cache.CacheProvider接口 
它是缓存插件与Hibernate之间的适配器。Hibernate为以上四个缓存插件提供了内置的适配器实现类。 
如果需要使用其他的缓存插件,只需要为这个插件提供实现了接口的类即可。

使用二级缓存

配置二级缓存
1.打开二级缓存
2.选择需要使用的二级缓存的持久化类,设置二级缓存的并发访问策略。
3.选择合适的缓存插件,配置缓存插件的配置文件。

我们演示使用EHCache插件

(1)先导包
(2)在hibernate.cfg.xml中配置使用二级缓存

<property name="hibernate.cache.use_second_level_cache">true</property>

(3)配置使用EHcache的实现类

<property name="hibernate.cache.region.factory_class">org.hibernate.cache.EhCacheRegionFactory</property>

Hibernate允许配置类和集合上设置二级缓存。还可以设置查询缓存。

(一)在类上设置二级缓存

  在hibernate.cfg.xml的<mapping>元素后面配置

<!--usage设置隔离级别,class设置哪个类-->
<class-cache usage="read-only" class="com.cad.domain.Customer"/>

  测试一下是否对象存到了二级缓存

 public class Demo {

            private Session session;

            @Test
public void test() {
//读取配置文件
Configuration conf=new Configuration().configure(); //根据配置创建factory
SessionFactory sessionfactory=conf.buildSessionFactory();
session = sessionfactory.openSession();
Transaction ts=session.beginTransaction();
//获取对象,打印select语句
Customer c1=session.get(Customer.class, 7);
//清除一级缓存
session.clear();
//再获取对象,没有打印select语句,说明对象存放在了二级缓存中
Customer c2=session.get(Customer.class, 7);
ts.commit();
session.close();
sessionfactory.close();
} }

(二) 在集合上设置二级缓存区

要把集合中的对象也给设置二级缓存区。

      <class-cache usage="read-only" class="com.cad.domain.Customer"/>
<class-cache usage="read-only" class="com.cad.domain.Order"/>
<!--collection设置对象中的集合-->
<collection-cache usage="read-only" collection="com.cad.domain.Customer.orders"/>

测试一下

public class Demo {

                private Session session;

                @Test
public void test() {
//读取配置文件
Configuration conf=new Configuration().configure(); //根据配置创建factory
SessionFactory sessionfactory=conf.buildSessionFactory();
session = sessionfactory.openSession();
Transaction ts=session.beginTransaction();
//打印select语句
Customer c1=session.get(Customer.class, 7);
for(com.cad.domain.Order o:c1.getOrders()){
System.out.println(o.getName());
}
//清空缓冲区
session.clear();
//再查找,不打印,说明集合中的对象都被放到了二级缓存中
Customer c2=session.get(Customer.class, 7);
for(com.cad.domain.Order o:c2.getOrders()){
System.out.println(o.getName());
}
ts.commit();
session.close();
sessionfactory.close();
} }

hibernate学习(缓存)的更多相关文章

  1. Hibernate学习---缓存机制

    前言:这些天学习效率比较慢,可能是手头的事情比较多,所以学习进度比较慢. 在之前的Hibernate学习中,我们无论是CURD,对单表查询还是检索优化,我们好像都离不开session,session我 ...

  2. [原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  3. Hibernate学习笔记(二)—— 实体规则&对象的状态&一级缓存

    一.持久化类 1.1 什么是持久化类? Hibernate是持久层的ORM映射框架,专注于数据的持久化工作.所谓的持久化,就是将内存中的数据永久存储到关系型数据库中.那么知道了什么是持久化,什么又是持 ...

  4. hibernate学习(9)——日志,一对一,二级缓存

    1.Hibernate中的日志 1  slf4j 核心jar  : slf4j-api-1.6.1.jar .slf4j是日志框架,将其他优秀的日志第三方进行整合. 整合导入jar包 log4j 核心 ...

  5. HIbernate学习笔记(八) hibernate缓存机制

    hibernate缓存 一. Session级缓存(一级缓存) 一级缓存很短和session的生命周期一致,因此也叫session级缓存或事务级缓存 hibernate一级缓存 那些方法支持一级缓存: ...

  6. Hibernate学习之缓存机制

    转自:http://www.cnblogs.com/xiaoluo501395377/p/3377604.html 一.N+1问题 首先我们来探讨一下N+1的问题,我们先通过一个例子来看一下,什么是N ...

  7. HIbernate学习笔记3 之 缓存和 对象的三种状态

    一.hibernate一级缓存 *  hibernate创建每个Session对象时,都会给该Session分配一块独立的缓冲区,用于存放Session查询出来的对象,这个分配给session的缓存区 ...

  8. Hibernate学习之一级缓存

    © 版权声明:本文为博主原创文章,转载请注明出处 Hibernate缓存: - 缓存是为了降低应用程序对物理数据源访问的频次,从而提供应用程序的运行性能的一种策略 - Hibernate缓存是提升和优 ...

  9. Hibernate学习笔记(二)

    2016/4/22 23:19:44 Hibernate学习笔记(二) 1.1 Hibernate的持久化类状态 1.1.1 Hibernate的持久化类状态 持久化:就是一个实体类与数据库表建立了映 ...

随机推荐

  1. 4.9cf自训9..

    cf401D 状态压缩dp好题,每次把新加入集合的数字放在最后即可 /* 它可以通过重新排列数字n, 它没有任何前导零, x除以m后的余数等于0. 每次把新加的数放在最后 dp[i][j]表示状态i下 ...

  2. Centos查看系统CPU个数、核心数、线程数

    1.查看 CPU 物理个数 grep 'physical id' /proc/cpuinfo | sort -u | wc -l 2.查看 CPU 核心数量 grep 'core id' /proc/ ...

  3. pta编程总结3

    7-1 抓老鼠啊~亏了还是赚了? (20 分) 某地老鼠成灾,现悬赏抓老鼠,每抓到一只奖励10元,于是开始跟老鼠斗智斗勇:每天在墙角可选择以下三个操作:放置一个带有一块奶酪的捕鼠夹(T),或者放置一块 ...

  4. Codeforces 840C. On the Bench 动态规划 排列组合

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF840C.html 题解 首先,我们可以发现,如果把每一个数的平方因子都除掉,那么剩下的数,不相等的数都可以相 ...

  5. python基础篇_004_装饰器函数

    python装饰器函数 1.装饰器函数引导 功能:计算函数执行时长 import time """ 方式一: 函数首位添加时间,差值就是函数执行时间 缺点:每个函数都要加 ...

  6. SA:利用SA算法解决TSP(数据是14个虚拟城市的横纵坐标)问题——Jason niu

    %SA:利用SA算法解决TSP(数据是14个虚拟城市的横纵坐标)问题——Jason niu X = [16.4700 96.1000 16.4700 94.4400 20.0900 92.5400 2 ...

  7. 大数据项目之_15_帮助文档_NTP 配置时间服务器+Linux 集群服务群起脚本+CentOS6.8 升级到 python 到 2.7

    一.NTP 配置时间服务器1.1.检查当前系统时区1.2.同步时间1.3.检查软件包1.4.修改 ntp 配置文件1.5.重启 ntp 服务1.6.设置定时同步任务二.Linux 集群服务群起脚本2. ...

  8. ISP PIPLINE (八) RGB2YUV

    what is the YUV? 暗电流来源1.YUV 是一种基本色彩空间, 人眼对亮度改变的敏感性远比对色彩变化大很多.亮度分量Y 要比色度分量U.V 重要得多. 所以, 可以适当地抛弃部分U.V分 ...

  9. ECMA Script 6_字符串_扩展_字符 是4字节还是2字节?_模板字符串

    ES6 字符串扩展 ES6 加强了对 Unicode 的支持,并且扩展了字符串对象 字符 的 Unicode 表示法 允许采用 \uxxxx 形式表示一个字符, 其中 xxxx 表示字符的 Unico ...

  10. document.querySelectorAll() 兼容 IE6

    不多说,直接上代码 // 使用 css 选择器获取元素对象 兼容性封装 Test Already. function getElementsByCss(cssStr){ if(document.que ...