Hibernate 的缓存机制

**

1、Hibernate 应用程序中按照缓存的范围,可以将缓存分为三类

**

(1.1)事务范围缓存(单Session,即一级缓存)
事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存。缓存的生命周期依赖于事务的生命周期:当事务结束时,缓存的生命周期也会结束。事务范围的缓存使用内存作为存储介质。Hibernate中的一级缓存就属于事务范围。

(1.2)应用范围缓存(单SessionFactory,即二级缓存)
应用范围的缓存可以被应用程序内的所有事务共享访问。缓存的生命周期依赖于应用的生命周期,当应用结束时,缓存的生命周期同时结束。应用范围的缓存可以使用内存或硬盘作为存储介质。Hibernate的二级缓存就属于应用范围。

(1.3)集群范围缓存(多SessionFactory)
在集群环境中,缓存被一个机器或多个机器的进程共享,缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形式。有些Hibernate的二级缓存第三方插件支持集群范围缓存。

**

2、Hibernate 应用程序中按照缓存的类型,可以将缓存分为两类

**

2.1 一级缓存

就是Session缓存,其实就是内存中的一块空间,在这个内存空间存放了相互关联的Java对象。Session缓存是事务级缓存。伴随着事务的开启而开启,伴随着事务的关闭而关闭。Session缓存由Hibernate进行管理。Session缓存,是Hibernate内置的。是不能被程序员取消的。即,只要使用Hibernate,就一定要使用,更确切地说,就一定在使用Session缓存。

当程序调用Session的load()方法、get()方法、save()方法、saveOrUpdate()方法、update()方法或查询接口方法时,Hibernate会对实体对象进行缓存。当通过load()或get()方法查询实体对象时,Hibernate会首先到缓存中查询,在找不到实体对象的情况下,Hibernate才会发出SQL语句到DB中查询。从而提高了Hibernate的使用效率。

一级缓存相关的方法:

    evict(Object o):从Session中删除指定对象clear():无参数,将Session缓存清空contains(Object o):判断指定对象是否在Session中存在flush():无参数,将Session中对象状态同步到DB中
@Test
public void test01_SQL() {//1. 获取SessionSession session = HbnUtils.getSession();try {//2. 开启事务session.beginTransaction();//3. 操作//session.get的时候,hibernate就将数据库中的数据加载到session缓存中,同时也会备份到快照中Student student = session.get(Student.class, 2);student.setName("n_2");session.update(student);//4. 事务提交//commit是唯一的同步时间点,当程序运行到同步时间点时,//hibernate先判断session缓存中的数据和快照中的数据是否相同,//如果不相同,则更新数据库,如果相同,则不更新数据库,//以上,两种情况,无论是否写了update,都成立session.getTransaction().commit();} catch (Exception e) {e.printStackTrace();//5. 事务回滚session.getTransaction().rollback();}
}

Session的刷新与同步:

Session的刷新是指,Session缓存中的数据的更新。Session的同步是指,将Session缓存中的数据同步更新到DB中。执行同步的时间点只有一个:事务的提交。

当代码中执行了对Session中现有数据的修改操作,即update()与delete()语句后,Session缓存并不会马上刷新,即并不会马上执行update与delete的SQL语句,而是在某个时间点到来时,才会刷新缓存,更新缓存中的数据。刷新的时间点主要有三个:

(1)执行Query查询(2)执行session.flush()(3)执行事务的提交

通过Session的setFlushMode()方法,可以设置缓存刷新模式:

在这里插入图片描述

注意:增删改操作,当刷新时间点到来时是否马上进行缓存更新,各自情况还是不同的。

删除操作,一到达刷新时间点,马上执行delete语句,更新Session中数据;

更新操作,到达刷新时间点后,是否马上执行update语句,更新Session中数据,还要看该修改内容是否与快照一致若一致,则执行,否则,则不执行;

插入操作,无需等到刷新时间点的到达,见到save()后马上执行insert语句。因为插入操作不是修改Session中已经的存在数据,而是给Session中添加数据。

2.2 二级缓存

二级缓存是SessionFactory级的缓存,其生命周期与SessionFactory一致。SessionFactory缓存可以依据功能和目的的不同而划分为内置缓存和外置缓存。

SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的副本,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来的SQL。SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。

SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的副本,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的二级缓存。

Hibernate本身只提供了二级缓存的规范,但并未实现,故需要第三方缓存产品的支持。常用的二级缓存第三方插件有:
EHCache、Memcached、OSCache、SwarmCache、JBossCache等。这些插件的功能各有侧重,各有特点。

在这里插入图片描述

二级缓存的执行:当Hibernate根据ID访问数据对象时,首先会从一级缓存Session中查找。若查不到且配置了二级缓存,则会从二级缓存中查找;若还查不到,就会查询数据库,把结果按照ID放入到缓存中。执行增、删、改操作时,会同步更新缓存。

二级缓存内容分类,根据缓存内容的不同,可以将Hibernate二级缓存分为四类:

(1)类缓存:缓存对象为实体类对象

(2)集合缓存:缓存对象为集合类对象

(3)更新时间戳缓存:

(4)查询缓存:缓存对象为查询结果

二级缓存的并发访问策略:

  • 事务型(transactional):隔离级别最高,对于经常被读但很少被改的数据,可以采用此策略。因为它可以防止脏读与不可重复读的并发问题。发生异常的时候,缓存也能够回滚(系统开销大)。

  • 读写型(read-write):对于经常被读但很少被改的数据,可以采用此策略。因为它可以防止脏读的并发问题。更新缓存的时候会锁定缓存中的数据。

  • 非严格读写型(nonstrict-read-write):不保证缓存与数据库中数据的一致性。对于极少被改,并且允许偶尔脏读的数据,可采用此策略。不锁定缓存中的数据。

  • 只读型(read-only):对于从来不会被修改的数据,可使用此策略。

二级缓存管理相关的方法:

与二级缓存管理相关的方法,一般都定义在Cache接口中。而Cache对象的获取,需要通过SessionFactory的getCache()方法:

Cache cache = sessionFactory.getCache();

二级缓存的配置(应用EHCache插件):

(1)导入ehcache的jar包,略

(2)在hibernate.cfg.xml中的<session-factory>元素中加入如下内容,开启二级缓存和注册二级缓存区域工厂:

    <!-- 开启二级缓存 --><property name="hibernate.cache.use_second_level_cache">true</property><!-- 注册二级缓存区域工厂 --><property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

(3)解压EHCache的核心Jar包ehcache-core-2.4.3.jar,将其中的一个配置文件ehcache-failsafe.xml直接放到项目的src目录下,并更名为ehcache.xml,注意其中的配置可以修改:

<defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"maxElementsOnDisk="10000000"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"><persistence strategy="localTempSwap"/></defaultCache>

(4)指定缓存内容:

指定缓存内容,即指定哪个类或哪个集合要进行二级缓存。指定的位置有两处:映射文件、主配置文件。这两种任选其一即可。它们的效果是相同的,但各有利弊:

在映射文件中指定缓存内容,查看其类的映射文件时,一眼就可看到类为缓存类,集合为缓存集合。但,弊端是,缓存的指定位置分散,缺乏项目的整体性。

在主配置文件中指定缓存内容,可一眼看到整个项目中所有缓存类与缓存集合。但,弊端是,缓存内容的指定与类映射分离。

映射文件中指定缓存内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.tongji.beans"><class name="Country"><!-- 指定当前类为类缓存对象 --><!-- <cache usage="read-only"/> --><id name="cid"><generator class="native"/></id><property name="cname"/><set name="ministers" cascade="save-update"><!-- 指定当前集合为集合缓存对象 --><!-- <cache usage="read-only"/> --><key column="countryId"/><one-to-many class="Minister"/></set></class></hibernate-mapping>

在主配置文件中指定缓存内容:在<mapping/>标签的后面指定类缓存与集合缓存

 <!-- 指定类缓存 --><class-cache usage="read-only" class="com.tongji.beans.Minister" /><class-cache usage="read-only" class="com.tongji.beans.Country" /><!-- 指定集合缓存 --><collection-cache usage="read-only"collection="com.tongji.beans.Country.ministers" />

补充:

(1)类缓存,缓存的是类的详情;集合缓存,在没有对集合中元素对应的类进行类缓存的时候,缓存的是所有元素的id。(2)Query查询缓存,即session.createQuery(hql)时进行缓存。说明以下三点:(1)Query查询的结果也会存放到一、二级缓存中(2)Query查询默认不会从一、二级缓存中读取数据,但可以改变:先在主配置文件中,开启Query查询总开关:<property name="hibernate.cache.use_query_cache">true</property>

查询时的代码:

@Test
public void test02() {//1. 获取SessionSession session = HbnUtils.getSession();try {//2. 开启事务session.beginTransaction();//3. 操作//第一次查询String hql = "from Country where cid=1";Country country1 = (Country) session.createQuery(hql).setCacheable(true).uniqueResult();System.out.println("第一次查询:Country = " + country1);//第二次查询Country country2 = (Country) session.createQuery(hql).setCacheable(true).uniqueResult();System.out.println("第二次查询:Country = " + country2);//将一级缓存数据清空session.clear();//第三次查询,从二级缓存中读取Country country3 = (Country) session.createQuery(hql).setCacheable(true).uniqueResult();System.out.println("第三次查询:Country = " + country3);//4. 事务提交session.getTransaction().commit();} catch (Exception e) {e.printStackTrace();//5. 事务回滚session.getTransaction().rollback();}}

(3)Query查询要从缓存中读取数据,必须保证Query所执行的HQL语句完全相同。因为Query查询,不仅将数据存放到了缓存中,还将HQL语句存放到了缓存中。

(4)修改时间戳:在二级缓存存放的对象中,比一级缓存中多出一个属性,updateTimeStamp,修改时间戳。只要这个属性发生改变,就说明有操作修改了DB中的数据,二级缓存中的该缓存对象已经不是最新数据,需要从DB中再次查询更新。

而Query接口的executeUpdate()方法所进行的更新,可以绕过一级缓存,但会修改二级缓存中缓存对象的updateTimeStamp值,由于该值的改变,二级缓存就会通过新的查询来更新缓存中的数据(一、二级缓存都更新了)。

**

三、拓展

**

3.1 N+1问题

https://www.cnblogs.com/xiaoluo501395377/p/3377604.html

https://www.cnblogs.com/quchengfeng/p/4111812.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313674.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET分布式大规模计算利器-Orleans(一)

写在前面Orleans是基于Actor模型思想的.NET领域的框架&#xff0c;它提供了一种直接而简单的方法来构建分布式大规模计算应用程序&#xff0c;而无需学习和应用复杂的并发或其他扩展模式。我在2015年下半年开始应用Orleans&#xff0c;当时公司的交易系统采用的架构就是基于Orl…

从单机应用到微服务,用户认证走几步?

用户认证指在用户访问服务的时候确认用户的身份&#xff0c;受限于HTTP无状态的特性&#xff0c;应用开发者需要自行实现用户认证相关功能。通常是用户登录时服务端生成通行证返回给客户端&#xff0c;客户端在接下来的请求中携带通行证&#xff0c;然后服务端通过校验该通行证…

编写优雅代码,从挖掉恶心的if/else 开始

背景长话短说&#xff0c; 作为开发人员经常需要根据条件灵活查询数据库&#xff0c;不管你是用rawsql 还是EFCore&#xff0c; 以下类似伪代码大家都可能遇到&#xff1a;特别是在大数据产品或者物联网产品中&#xff0c;字段甚多&#xff1b;if/else 写到死&#xff0c;一边写…

.NET Conf 2019 大会上发布.NET Core 3.0

北京时间今天凌晨如期在.NET Conf 上发布.NET Core 3.0,Keynotes 由Scott Hunter 主演&#xff0c;主要围绕.NET Core 3.0的新特性和社区展开。多功能性是.Net Core 成为我们的生活一部分的最好解释。如果您是Web开发人员还是想开发桌面或移动应用程序&#xff0c;如果您是游戏…

Spring AOP实现原理

先说结论&#xff1a; Spring AOP采用的是JDK动态代理 CGLIB动态代理模式。当当前类为接口的实现时&#xff0c;采用JDK动态代理&#xff0c;否则用CGLIB、 1、AOP 的存在价值 在传统 OOP 编程里以对象为核心&#xff0c;整个软件系统由系列相互依赖的对象所组成&#xff0c…

微软推出Python免费在线教程视频

开源中国曾报道过最近微软针对 Python 初学者&#xff0c;推出了一套免费的教程视频。这套视频名为 Python for Beginners&#xff0c;该在线教学视频由微软高级项目经理 Christopher Harrison、以及微软 AI Gaming 的商业开发经理 Susan Ibach 共同讲解&#xff0c;在课程中加…

推荐neter常用优秀开源项目系列之一

.net社区有很多优秀的开源项目&#xff0c;我们今天先推荐6个开源项目&#xff1b;1.MassTransitMassTransit 是一个自由、开源、轻量级的消息总线, 用于使用. NET 框架创建分布式应用程序。MassTransit在现有消息传输上提供了一组广泛的功能, 从而使开发人员能够友好地使用基于…

聊聊高并发下库存加减那些事儿——“异步扣减库存”

聊聊高并发下库存加减那些事儿不定期福利发放哦聊聊高并发下库存加减那些事儿背景一般在日常开发中经常会遇到打折促销&#xff0c;秒杀活动&#xff0c;就如拼多多最近的4999抢券买爱疯11促销活动&#xff0c;毕竟谁的钱也不是大风刮来的&#xff0c;有秒杀有促销必定带来大量…

什么是MVC

什么是MVC&#xff1f; MVC全名是Model View Controller&#xff0c;是模型(model)&#xff0d;视图(view)&#xff0d;控制器(controller)的缩写&#xff0c;一种软件设计典范。 用一种业务逻辑、数据、界面显示分离的方法&#xff0c;将业务逻辑聚集到一个部件里面&#xf…

SpringMVC 、Struts的区别

先说结论&#xff1a;目前Spring MVC已经一统江山&#xff0c;Struts正在被抛弃 1、Spring MVC原理 Spring 体系&#xff1a; Spring MVC工作流程图 SpringMVC的工作流程描述 1. 用户向服务器发送请求&#xff0c;请求被Spring前端控制Servelt DispatcherServlet捕获&#x…

基于Asp.Net Core MVC和AdminLTE的响应式管理后台之侧边栏处理

说明&#xff1a;.NET Core版本为:2.2 AdminLTE版本为:2.4.18 Bootstrap版本为:3.4.1 font-awesome版本为:4.7.01、新建项目&#xff1a;AdminLteDemo&#xff0c;添加区域Admin 在Areas/Admin/Views文件夹添加文件并分别添加如下代码&#xff1a;_ViewImports.cshtmladdTagHel…

Spring boot——起步依赖

一、起步依赖 1、是什么 本质上是一个Maven项目对象模型&#xff08;Project Object Model&#xff0c; POM&#xff09;&#xff0c; 定义了对其他库的传递依赖&#xff0c;这些东西加在一起即支持某项功能。 比如&#xff1a; spring-boot-dependencies^ spring-boot-pare…

[翻译] ASP.NET Core 3.0 的新增功能

全文翻译自微软官方文档英文版 Whats new in ASP.NET Core 3.0本文重点介绍了 ASP.NET Core 3.0 中最重要的更改&#xff0c;并提供相关文档的连接。BlazorBlazor 是 ASP.NET Core 中的一个新的框架&#xff0c;用于使用 .NET 构建交互式的客户端 Web UI&#xff1a;使用 C# 而…

Sprig boot自动配置

1、概述 Spring Boot是Spring旗下众多的子项目之一&#xff0c;其理念是约定优于配置&#xff0c;它通过实现了自动配置&#xff08;大多数用户平时习惯设置的配置作为默认配置&#xff09;的功能来为用户快速构建出标准化的应用。Spring Boot的特点可以概述为如下几点&#x…

.NET Core 3.0稳定版发布

一年一度的 .NET 开发者盛会 .NET Conf 2019 已正式开始了&#xff08;举办时间为 9.23-9.25&#xff09;。大会第一天最重磅也是最激动人心的消息莫过于 .NET Core 3.0 稳定版的发布。.NET 项目管理总监 Scott Hunter 在大会宣布了这则消息&#xff0c;并在主题演讲环节围绕 .…

深入理解 Spring Boot Starters 原理(手写Spring boot Start)

一、Spring Boot Starter诞生原因 Spring Boot Starter是在SpringBoot组件中被提出来的一种概念&#xff0c;stackoverflow上面已经有人概括了这个starter是什么东西&#xff0c;想看完整的回答戳这里 Starter POMs are a set of convenient dependency descriptors that you …

记一次中小公司的研发问题

作者&#xff1a;zollty&#xff0c;资深程序员和架构师&#xff0c;私底下是个爱折腾的技术极客&#xff0c;架构师社区合伙人&#xff01;一、一些不好的现状&#xff0c;及对应的改进方法1、前后端代码绑定在一起&#xff0c;很难维护&#xff0c;前端UI做得太差&#xff0c…

ASP.NET Core 3.0 使用gRPC

一.简介gRPC 是一个由Google开源的&#xff0c;跨语言的&#xff0c;高性能的远程过程调用&#xff08;RPC&#xff09;框架。gRPC使客户端和服务端应用程序可以透明地进行通信&#xff0c;并简化了连接系统的构建。它使用HTTP/2作为通信协议&#xff0c;使用 Protocol Buffers…

Codeforces Round #739 (Div. 3)(AK实况)

Codeforces Round #739 (Div. 3) A. Dislike of Threes 找到第kkk个既不是333的倍数&#xff0c;个位数上也不是333的数&#xff0c;也已预处理然后O(1)O(1)O(1)输出&#xff0c;也可直接forforfor循环暴力。 #include <bits/stdc.h>using namespace std;int main() {/…

利用Helm简化Kubernetes应用部署(2)

目录定义Charts 使用Helm部署Demo Helm常用操作命令 定义Charts回到之前的“charts”目录&#xff0c;我们依次进行解读并进行简单的修改。Chart.yaml配置示例&#xff1a;apiVersion: v1 appVersion: "1.1" description: A demo Helm chart for Kubernetes name:…