一、why(为什么要用Hibernate缓存?)

Hibernate是一个持久层框架,经常访问物理数据库。

为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。

缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源

的数据。

二、what(Hibernate缓存原理是怎样的?)

Hibernate缓存包括两大类:Hibernate一级缓存和Hibernate二级缓存。

1.Hibernate一级缓存又称为“Session的缓存”。

Session内置不能被卸载,Session的缓存是事务范围的缓存(Session对象的生命周期通常对应一个数据库事务或者一个应用事

务)。一级缓存中,持久化类的每个实例都具有唯一的OID。

2.Hibernate二级缓存又称为“SessionFactory的缓存”。

由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能

出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。

第二级缓存是可选的,是一个可配置的插件,默认下SessionFactory不会启用这个插件。

Hibernate提供了org.hibernate.cache.CacheProvider接口,它充当缓存插件与Hibernate之间的适配器。

什么样的数据适合存放到第二级缓存中?   

1) 很少被修改的数据   

2) 不是很重要的数据,允许出现偶尔并发的数据   

3) 不会被并发访问的数据   

4) 常量数据   

不适合存放到第二级缓存的数据?   

1) 经常被修改的数据   

2) 绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发   

3) 与其他应用共享的数据。

3.Session的延迟加载实现要解决两个问题:正常关闭连接和确保请求中访问的是同一个session。

Hibernate session就是java.sql.Connection的一层高级封装,一个session对应了一个Connection。http请求结束后正确的关闭

session(过滤器实现了session的正常关闭);延迟加载必须保证是同一个session(session绑定在ThreadLocal)。

4.Hibernate查找对象如何应用缓存?

当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;

如果都查不到,再查询数据库,把结果按照ID放入到缓存删除、更新、增加数据的时候,同时更新缓存。

5.一级缓存与二级缓存的对比图。

一级缓存

二级缓存

存放数据的形式

相互关联的持久化对象

对象的散装数据

缓存的范围

事务范围,每个事务都拥有单独的一级缓存

进程范围或集群范围,缓存被同一个进程或集群范围内所有事务共享

并发访问策略

由于每个事务都拥有单独的一级缓存不会出现并发问题,因此无须提供并发访问策略

由于多个事务会同时访问二级缓存中的相同数据,因此必须提供适当的并发访问策略,来保证特定的事务隔离级别

数据过期策略

处于一级缓存中的对象永远不会过期,除非应用程序显示清空或者清空特定对象

必须提供数据过期策略,如基于内存的缓存中对象的最大数目,允许对象处于缓存中的最长时间,以及允许对象处于缓存中的最长空闲时间

物理介质

内存

内存和硬盘,对象的散装数据首先存放到基于内存的缓存中,当内存中对象的数目达到数据过期策略的maxElementsInMemory值,就会把其余的对象写入基于硬盘的缓存中

缓存软件实现

在Hibernate的Session的实现中包含

由第三方提供,Hibernate仅提供了缓存适配器,用于把特定的缓存插件集成到Hibernate中

启用缓存的方式

只要通过Session接口来执行保存,更新,删除,加载,查询,Hibernate就会启用一级缓存,对于批量操作,如不希望启用一级缓存,直接通过JDBCAPI来执行

用户可以再单个类或类的单个集合的粒度上配置第二级缓存,如果类的实例被经常读,但很少被修改,就可以考虑使用二级缓存,只有为某个类或集合配置了二级缓存,Hibernate在运行时才会把它的实例加入到二级缓存中

用户管理缓存的方式

一级缓存的物理介质为内存,由于内存的容量有限,必须通过恰当的检索策略和检索方式来限制加载对象的数目,Session的evit()方法可以显示的清空缓存中特定对象,但不推荐

二级缓存的物理介质可以使内存和硬盘,因此第二级缓存可以存放大容量的数据,数据过期策略的maxElementsInMemory属性可以控制内存中的对象数目,管理二级缓存主要包括两个方面:选择需要使用第二级缓存的持久化类,设置合适的并发访问策略;选择缓存适配器,设置合适的数据过期策略。SessionFactory的evit()方法也可以显示的清空缓存中特定对象,但不推荐

三、how(Hibernate的缓存机制如何应用?)

1.  一级缓存的管理:

evit(Object obj)  将指定的持久化对象从一级缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为

游离对象。

clear()  将一级缓存中的所有持久化对象清除,释放其占用的内存资源。

contains(Object obj) 判断指定的对象是否存在于一级缓存中。

flush() 刷新一级缓存区的内容,使之与数据库数据保持同步。

2.一级缓存应用: save()。当session对象调用save()方法保存一个对象后,该对象会被放入到session的缓存中。 get()和load()。当

session对象调用get()或load()方法从数据库取出一个对象后,该对象也会被放入到session的缓存中。 使用HQL和QBC等从数据库

中查询数据。

public class Client
{public static void main(String[] args){Session session = HibernateUtil.getSessionFactory().openSession();Transaction tx = null;try{/*开启一个事务*/tx = session.beginTransaction();/*从数据库中获取id="402881e534fa5a440134fa5a45340002"的Customer对象*/Customer customer1 = (Customer)session.get(Customer.class, "402881e534fa5a440134fa5a45340002");System.out.println("customer.getUsername is"+customer1.getUsername());/*事务提交*/tx.commit();System.out.println("-------------------------------------");/*开启一个新事务*/tx = session.beginTransaction();/*从数据库中获取id="402881e534fa5a440134fa5a45340002"的Customer对象*/Customer customer2 = (Customer)session.get(Customer.class, "402881e534fa5a440134fa5a45340002");System.out.println("customer2.getUsername is"+customer2.getUsername());/*事务提交*/tx.commit();System.out.println("-------------------------------------");/*比较两个get()方法获取的对象是否是同一个对象*/System.out.println("customer1 == customer2 result is "+(customer1==customer2));}catch (Exception e){if(tx!=null){tx.rollback();}}finally{session.close();}}
}
结果
Hibernate: selectcustomer0_.id as id0_0_,customer0_.username as username0_0_,customer0_.balance as balance0_0_ fromcustomer customer0_ wherecustomer0_.id=?
customer.getUsername islisi
-------------------------------------
customer2.getUsername islisi
-------------------------------------
customer1 == customer2 result is true

输出结果中只包含了一条SELECT SQL语句,而且customer1 == customer2 result is true说明两个取出来的对象是同一个对象。其

原理是:第一次调用get()方法, Hibernate先检索缓存中是否有该查找对象,发现没有,Hibernate发送SELECT语句到数据库中取

出相应的对象,然后将该对象放入缓存中,以便下次使用,第二次调用get()方法,Hibernate先检索缓存中是否有该查找对象,发现

正好有该查找对象,就从缓存中取出来,不再去数据库中检索。

3.二级缓存的管理:

evict(Class arg0, Serializable arg1)将某个类的指定ID的持久化对象从二级缓存中清除,释放对象所占用的资源。

sessionFactory.evict(Customer.class, new Integer(1));

evict(Class arg0)  将指定类的所有持久化对象从二级缓存中清除,释放其占用的内存资源。

sessionFactory.evict(Customer.class);

evictCollection(String arg0)  将指定类的所有持久化对象的指定集合从二级缓存中清除,释放其占用的内存资源。

sessionFactory.evictCollection("Customer.orders");

4.二级缓存的配置

常用的二级缓存插件

EHCache  org.hibernate.cache.EhCacheProvider

OSCache  org.hibernate.cache.OSCacheProvider

SwarmCahe  org.hibernate.cache.SwarmCacheProvider

JBossCache  org.hibernate.cache.TreeCacheProvider

<!-- EHCache的配置,hibernate.cfg.xml -->
<hibernate-configuration><session-factory><!-- 设置二级缓存插件EHCache的Provider类--><property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property><!-- 启动"查询缓存" --><property name="hibernate.cache.use_query_cache">true</property></session-factory></hibernate-configuration>
<!-- ehcache.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<ehcache><!--缓存到硬盘的路径--><diskStore path="d:/ehcache"></diskStore><!--默认设置maxElementsInMemory : 在內存中最大緩存的对象数量。eternal : 缓存的对象是否永远不变。timeToIdleSeconds :可以操作对象的时间。timeToLiveSeconds :缓存中对象的生命周期,时间到后查询数据会从数据库中读取。overflowToDisk :内存满了,是否要缓存到硬盘。--><defaultCache maxElementsInMemory="200" eternal="false" timeToIdleSeconds="50" timeToLiveSeconds="60" overflowToDisk="true"></defaultCache><!--指定缓存的对象。下面出现的的属性覆盖上面出现的,没出现的继承上面的。--><cache name="com.suxiaolei.hibernate.pojos.Order" maxElementsInMemory="200" eternal="false" timeToIdleSeconds="50" timeToLiveSeconds="60" overflowToDisk="true"></cache>
</ehcache>

注意,ehcache.xml是对于二级缓存的配置文件,其中包括了硬盘地址(如果设置了允许写入硬盘)、默认二级缓存配置、有命名的二级缓存配置等。该文件也放置于src目录

下。

<!-- *.hbm.xml -->
<?xml version="1.0" encoding='UTF-8'?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping><class><!-- 设置该持久化类的二级缓存并发访问策略 read-only read-write nonstrict-read-write transactional--><cache usage="read-write"/>    </class>
</hibernate-mapping>

上面是用xml文件进行配置的,如果采用Annotation来配置则更加简便一些。

annotation的配置方法:

配置好后直接在允许写入二级缓存的实体类名上加@cache注解即可。该注解包含三个属性值:

①usage:必选,设置给定缓存的并发策略(常用的为READ_WRITE)

②region:可选,缓存范围,选择采用哪个二级缓存配置,如果缺省,则选择默认的缓存配置。

③include:可选,值为all时包括了所有的属性,为non-lazy时仅含非延迟类属性,默认为all。

若存在一对多的关系,想要在在获取一方的时候将关联的多方缓存起来,需要在集合属性下添加<cache>子标签,这里需要将关联

的对象的hbm文件中必须在存在<class>标签下也添加<cache>标签,不然Hibernate只会缓存OID。

<hibernate-mapping><class name="com.suxiaolei.hibernate.pojos.Customer" table="customer"><!-- 主键设置 --><id name="id" type="string"><column name="id"></column><generator class="uuid"></generator></id><!-- 属性设置 --><property name="username" column="username" type="string"></property><property name="balance" column="balance" type="integer"></property><set name="orders" inverse="true" cascade="all" lazy="false" fetch="join"><cache usage="read-only"/><key column="customer_id" ></key><one-to-many class="com.suxiaolei.hibernate.pojos.Order"/></set></class></hibernate-mapping>

常用缓存算法介绍:

1、LRU:Least Recently Used

2、LFU:Least Frequently Used

3、FIFO:First In First Out

对于ehcache,可以在属性配置中添加memoryStoreEvictionPolicy="xxx"配置缓存算法


四、查询缓存

在hibernate的使用中,大家多数时间都在讨论一级缓存和二级缓存,而往往忽略了查询缓存。其实hibernate的查询缓存在使用过程中也起着同样重要的作用。hibernate的查询缓存是主要是针对普通属性结果集的缓存, 而对于实体对象的结果集只缓存id。在一级缓存,二级缓存和查询缓存都打开的情况下作查询操作时这样的:查询普通属性,会先到查询缓存中取,如果没有,则查询数据库;查询实体,会先到查询缓存中取id,如果有,则根据id到缓存(一级/二级)中取实体,如果缓存中取不到实体,再查询数据库。

和一级/二级缓存不同,查询缓存的生命周期 ,是不确定的,当前关联的表发生改变时,查询缓存的生命周期结束。

查询缓存是基于二级缓存的,因此配置查询缓存需要先行配置好二级缓存,之后加入如下配置:

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

同时还需要在程序中显式的进行启用:

query.setCacheable(true);

之后当用同样的查询时,哪怕不在一个session中,都不会重复的发送sql语句。

需要注意的一点是,一级缓存和二级缓存都是缓存的实体对象,然而查询缓存缓存的是查询出来的部分属性结果集和实体的

Id(注意,并不是实体本身)。

Hibernate学习——(十二)Hibernate缓存机制(一级、二级、查询)相关推荐

  1. Mybatis(五) 延迟加载和缓存机制(一级二级缓存)

    踏踏实实踏踏实实,开开心心,开心是一天不开心也是一天,路漫漫其修远兮. --WZY 一.延迟加载 延迟加载就是懒加载,先去查询主表信息,如果用到从表的数据的话,再去查询从表的信息,也就是如果没用到从表 ...

  2. 【HIBERNATE框架开发之九】HIBERNATE 性能优化笔记!(遍历、一级/二级/查询/缓存、乐观悲观锁等优化算法)...

    本站文章均为 李华明Himi 原创,转载务必在明显处注明:  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/hibernate/825.html 1. ...

  3. 【Hibernate框架开发之九】Hibernate 性能优化笔记!(遍历、一级/二级/查询/缓存/乐观悲观锁等优化算法)...

    1.   循环分页或者循环进行部分读取处理数据的时候,使用 session.clear() ; 2.    对应1+N(N+1)问题使用如下解决方式: 1): 使用createCriteria进行查询 ...

  4. Spring 源码分析衍生篇十 :Last-Modified 缓存机制

    文章目录 一.前言 二.Last-Modify 三.实现方案 1. 实现 org.springframework.web.servlet.mvc.LastModified接口 1.1. 简单演示 1. ...

  5. OpenCV与图像处理学习十二——图像形状特征之HOG特征

    OpenCV与图像处理学习十二--图像形状特征之HOG特征 一.图像特征理解 1.1 颜色特征 1.2 纹理特征 1.3 形状特征 1.4 空间关系特征 二.形状特征描述 2.1 HOG特征 2.1. ...

  6. PyTorch框架学习十二——损失函数

    PyTorch框架学习十二--损失函数 一.损失函数的作用 二.18种常见损失函数简述 1.L1Loss(MAE) 2.MSELoss 3.SmoothL1Loss 4.交叉熵CrossEntropy ...

  7. (转)SpringMVC学习(十二)——SpringMVC中的拦截器

    http://blog.csdn.net/yerenyuan_pku/article/details/72567761 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter, ...

  8. 【FastAPI 学习十二】定时任务篇 (移步博客园或个人网站 无广告,界面清爽整洁)

    声明 目前个人放弃CSDN平台,文章只发布于个人网站和博客园 博客园地址 [FastAPI 学习十二]定时任务篇

  9. C1认证学习十二(网络拓扑)

    C1认证学习十二(网络拓扑) 任务背景 互联网是一个广义的概念,它泛指是一切通过网路连接在一起的计算机的集合,所以,若果只是局部观察,那就不能再说互联网是一个互联的了,那么,如果说对于一个公司来说,具 ...

  10. Js高级程序设计第三版学习(十二章)

                                  Js高级程序设计第三版学习(十二章) 第十二章 DOM2和DOM3   1.样式: 访问样式属性 任何支持style特性的HTML元素都有一 ...

最新文章

  1. 互联网造车上半场即将收尾,下半场才是真考验
  2. 30段极简Python代码:这些小技巧你都Get了么(附代码链接)
  3. Apache Dubbo 高危漏洞通告
  4. oracle同库复制schema,使用impdp复制oracle的schema数据迁移 | 学步园
  5. Spring Boot学习总结(7)——SpringBoot之于Spring优势
  6. c++ mfc程序 屏幕只显示部分内容_Visual C++ MFC 简明教程
  7. 从MDK4到MDK5之“盘古开天辟地”
  8. 关于STM32xE系列芯片STOP模式下使用RTC唤醒所遇到的问题记录
  9. 四、案例:北京二手房价影响因素分析
  10. 用Matlab进行2ASK仿真程序流程图,matlab画流程图
  11. 苹果开发者过期续费流程
  12. Java并发编程synchronized详解
  13. 实现NFS HA共享目录
  14. MsCOCO数据集标注详解
  15. Spring入门实例
  16. 不想升级,iOS系统自动更新可彻底关闭! 2016-05-23 16:38 更新/自动/on 昨天笔者发布了一篇关于iOS系统总提醒更新,到底要不要升级的文章,不少读者在微信上留言给笔者, iPhon
  17. 最值得珍藏的420个生活小窍门
  18. Java程序员日常开发提效工具(谷歌,Idea)-长期更新
  19. iOS上二维码和一维码识别系列二
  20. 【整理】Matlab常用函数

热门文章

  1. 《汽车行业面向智能制造的BOM物料管理》拆书心得—第二章 转型期需要什么样的BOM体系
  2. 名帖149 陆启成 楷书《陈眉公小窗幽记》
  3. 超详细Java学习知识点-不定更新
  4. Java企业级应用架构设计中的分布式结构
  5. 乐高机器人走进图书馆活动方案_综合实践活动——走进图书馆
  6. 第6课 用SI编写Hello World智能合约,开启EOS之旅
  7. jquery在线地址,layui在线地址,bootstrap在线地址以及把线上地址保存到本地
  8. STM32/51单片机实训day3——点亮LED灯、闪烁LED灯(一)理论
  9. 多线程爬取小米应用商店
  10. 2023 4月份 华为硬件开发岗位实习生机考回忆