22. Hibernate 性能之缓存

news2024/11/15 21:37:52

1. 前言

本节和大家一起聊聊性能优化方案之:缓存。通过本节学习,你将了解到:

  • 什么是缓存,缓存的作用;
  • HIbernate 中的缓存级别;
  • 如何使用缓存。

2. 缓存

2.1 缓存是什么

现实世界里,缓存是一个无处不在的概念。

家里的米桶中都会储存大米,需要下锅时,直接从米桶里拿出来,而不是等米下锅时去商店采购。只有等到米桶中没有米时,才会去商店。

米桶就是一个类似于缓存的存储体,它的作用是用来缓存大米。

程序中,通俗讲,缓存就是一个用来临时存储数据的地方,便于需要时伸手便可拿到。

更专业上讲,缓存可以在两个速度不匹配的设备之间建立一个缓冲带,适配两者速度。

2.2 Hibernate 中的为什么需要缓存

要搞清楚 Hibernate 为什么需要缓存,那就要了解 Hibernate 使用缓存做什么?

Hibernate 的任务是帮助开发者发送 SQL 语句,从数据库中获取数据。

这个过程并不轻松。从微观角度上讲,Hibernate 要背上行李,通过纵横交织的网络交通,到达数据库服务器,获取数据。然后背起数据,继续行走在四通八达的网络交通,回到程序中。

运气不好时,碰到网络拥堵,就会产生延迟,遇到网络断线,则会丢失数据。

理论上讲,对于每次的数据请求,这个过程都是必须的。

但是,如果多次的请求是同样数据的时候,也就是用户的请求 SQL 是一样的时候,有必要这么不停地来往于数据库服务器吗?

面对这种情况,Hibernate 提供的缓存就起作用了,可以缓存曾经从数据库中获取过的数据。如果下次再需要时,只需要从缓存中获取,而无需翻山涉水,通过网络获取。

Hibernate 的缓存主要是存储曾经操作过的数据,程序逻辑向 Hibernate 发送数据请求操作时,Hibernate 会先查询缓存中有没有,如果存在,则直接从缓存中获取,没有时,才会行走于网络通道,从数据库中获取。

3. Session 缓存

Hibernate 提供有一级和二级缓存,一级缓存也叫 Session 缓存,二级缓存也叫 SessionFactory 缓存。

前面课程中和大家聊过,Session 的使用原则是,需要时创建,用完后关闭,其作用域一般为方法级别。

一级缓存的生命周期和 Session 是一致的,所以,一级缓存中所存储的数据其生命周期也不长,其实际意义就论情况来看了。

SessionFactory 在前面也讨论过,SessionFactory 是应用程序级别的生命周期,所以与其关联的缓存中所保存的数据也可以长时间存在。

默认情况下,Hibernate 的一级缓存是可以直接使用的,二级缓存是没有打开的。需要根据实际情况进行选择。

验证一级缓存

需求:在 Session 关闭之前,连续查询相同的学生两次。

Session session = sessionFactory.openSession();
Transaction transaction = null;
Student stu = null;
try {
	transaction = session.beginTransaction();
	stu = (Student) session.get(Student.class, new Integer(1));
	System.out.println(stu.getStuName());
	// 查询前面查询过的学生
	System.out.println("--------------第二次查询------------------");
	stu = (Student) session.get(Student.class, new Integer(1));
	System.out.println(stu.getStuName());
	transaction.commit();
} catch (Exception e) {
	transaction.rollback();
} finally {
	session.close();
}

运行结果如下:

Hibernate: 
    select
        student0_.stuId as stuId1_3_0_,
        student0_.classRoomId as classRoo6_3_0_,
        student0_.stuName as stuName2_3_0_,
        student0_.stuPassword as stuPassw3_3_0_,
        student0_.stuPic as stuPic4_3_0_,
        student0_.stuSex as stuSex5_3_0_ 
    from
        Student student0_ 
    where
        student0_.stuId=?
Hibernate
--------------第二次查询------------------
Hibernate

从输出结果中能得到什么结论?

只有在第一次查询的时候,Hibernate 才会向数据库发送 SQL 语句请求,第二查询时,不需要再发送 SQL 请求,因为缓存中已经存在。

稍微改动一下上述实例,创建两个 Session 对象,用来查询同一个学生:

Session session = sessionFactory.openSession();
Transaction transaction = null;
Student stu = null;
try {
	transaction = session.beginTransaction();
	System.out.println("--------------第一次查询------------------");
	stu = (Student) session.get(Student.class, new Integer(1));
	System.out.println(stu.getStuName());
} catch (Exception e) {
	transaction.rollback();
} finally {
	session.close();
}

session = sessionFactory.openSession();
try {
	transaction = session.beginTransaction();
	// 查询前面查询过的学生
	System.out.println("--------------第二次查询------------------");
	stu = (Student) session.get(Student.class, new Integer(1));
	System.out.println(stu.getStuName());
	transaction.commit();
} catch (Exception e) {
	transaction.rollback();
} finally {
	session.close();
}

查看控制台上的输出结果:

Hibernate: 
    select
        student0_.stuId as stuId1_3_0_,
        student0_.classRoomId as classRoo6_3_0_,
        student0_.stuName as stuName2_3_0_,
        student0_.stuPassword as stuPassw3_3_0_,
        student0_.stuPic as stuPic4_3_0_,
        student0_.stuSex as stuSex5_3_0_ 
    from
        Student student0_ 
    where
        student0_.stuId=?
Hibernate
--------------第二次查询------------------
Hibernate: 
    select
        student0_.stuId as stuId1_3_0_,
        student0_.classRoomId as classRoo6_3_0_,
        student0_.stuName as stuName2_3_0_,
        student0_.stuPassword as stuPassw3_3_0_,
        student0_.stuPic as stuPic4_3_0_,
        student0_.stuSex as stuSex5_3_0_ 
    from
        Student student0_ 
    where
        student0_.stuId=?
Hibernate

每次查询都会发送 SQL 请求,这是因为 Session 缓存中的数据只能提供给本 Session 对象使用。不能跨 Session 使用。

  • 当调用 save ()、update () 或 saveOrUpdate () 方法传递一个对象时,或使用 load ()、 get ()、list ()、iterate () 方法获得一个对象时,该对象都将被加入到 Session 的内部缓存中;
  • 可以通过调用 close()、clear()、evict() 方法手工清空缓存中的数据。

前面说过的,Session 生命周期很短,与 Session 关联的一级缓存的生命周期也很短,所以缓存的命中率是很低的。其对系统性能的改善也有限得很。Session 内部缓存的主要作用是保持 Session 内部数据状态同步。

4. SessionFactory 缓存

SessionFactory 缓存也称其为二级缓存,是应用程序级别的缓存。二级缓存在默认情况下是没有启动的,如果开发者想使用二级缓存所提供的功能,则需要通过一系列的操作流程方能让其现身。

Hibernate 本身也提供有二级缓存的功能模块,但只建议用于测试或学习过程。对于生产环境,Hibernae 建议使用专业的第三方缓存框架,如 EhCache 缓存框架。

常用缓存框架:

  • EhCache;
  • OSCache;
  • SwarmCache;
  • JBossCache。

启动二级缓存

1. 在 Hibernate 的主配置文件中启动并指定二级缓存的实现者;

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

2. 添加 EhCache 相关的 JAR 包。这些 JAR 包都可以在下载的 Hibernate 框架包的 lib 文件夹中找到;

  • ehcache-core-2.4.3.jar;
  • hibernate-ehcache-4.2.0.Final.jar。

3. 在项目的 src 中添加 EhCache 缓存框架的配置文件 ehcache.xml

这个配置文件可以在下载的 Hibernate 框架包中的 project 目录下的 etc 中找到。此配置文件中的内容用来配置缓存管理相关信息。

<ehcache>  
<diskStore path="java.io.tmpdir"/>  
<defaultCache  
        maxElementsInMemory="10000"  
        eternal="false"  
        timeToIdleSeconds="120"  
        timeToLiveSeconds="120"  
        overflowToDisk="true"  
        />  
</ehcache>  

配置说明:

  • maxElementsInMemory: 缓存最大数目;
  • eternal : 缓存是否持久;
  • overflowToDisk : 是否保存到磁盘,当系统当机时;
  • timeToIdleSeconds : 当缓存闲置 n 秒后销毁;
  • timeToLiveSeconds : 当缓存存活 n 秒后销毁。
  1. 在需要缓存的实体类上添加 @cache 注解
@Cache(usage=CacheConcurrencyStrategy.TRANSACTIONAL,include="all",region="student")  

只有被 @Cache 注解的实体才会被存储进二级缓存中,此注解有一个 usage 属性,用来配置缓存的策略,是一个枚举类型,有如下几种选择:

  • CacheConcurrencyStrategy.NONE
  • CacheConcurrencyStrategy.NONSTRICT_READ_WRITE: 非严格读写缓存;
  • CacheConcurrencyStrategy.READ_ONLY: 只读缓存;
  • CacheConcurrencyStrategy.READ_WRITE: 读写缓存;
  • CacheConcurrencyStrategy.TRANSACTIONAL: 事务缓存。

Region 指定二级缓存中的区域名,默认为类或者集合的名字。
include 有几个选项,non-lazy 当属性延迟抓取打开时,标记为 lazy=“true” 的实体的属性可能无法被缓存。

做完上面的事情后,再执行前面的两个 Session 对象查询同一个学生的代码,再查看控制台上的信息:

Hibernate: 
    select
        student0_.stuId as stuId1_1_0_,
        student0_.classRoomId as classRoo5_1_0_,
        student0_.stuName as stuName2_1_0_,
        student0_.stuPassword as stuPassw3_1_0_,
        student0_.stuSex as stuSex4_1_0_ 
    from
        Student student0_ 
    where
        student0_.stuId=?
学生姓名:Hibernate
--------------第二次查询------------------
学生姓名:Hibernate

第一次查询时,需要发送 SQL 请求,第二查询时,不再发送 SQL 请求,因为查询过的信息已经被存储在了二级缓存中,Hibernate 会直接从缓存查询。

二级缓存并不支持缓存 Blob 类型的数据。

5. 小结

本节和大家一起了解了 Hibernate 提供的缓存机制,Hibernate 提供了一级缓存和二级缓存。一级缓存因生命周期较短,主要用于内部服务。二级缓存因生命周期较长,命中率会较高,缓存中一般存放经常被访问、改动不频繁、数量有限的数据。

有了缓存机制的加持,HIbernate 在响应开发者的请求时,又会少了许多延迟。速度对于程序来讲,是一个重要的性能指标。

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

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

相关文章

纪念二2024.07 federated-解决mysql跨库联表问题

若需要创建FEDERATED引擎表&#xff0c;则目标端实例要开启FEDERATED引擎。从MySQL5.5开始FEDERATED引擎默认安装 只是没有启用&#xff0c;进入命令行输入 show engines ; FEDERATED行状态为NO。 mysql安装配置文件 一、连接工具查看是否开启federated show engines 二、m…

VMware Workstation17 安装 CentOS7 教程

今天给伙伴们分享一下VMware Workstation17 安装 CentOS7 教程&#xff0c;希望看了有所收获。 我是公众号「想吃西红柿」「云原生运维实战派」作者&#xff0c;对云原生运维感兴趣&#xff0c;也保持时刻学习&#xff0c;后续会分享工作中用到的运维技术&#xff0c;在运维的路…

JS【详解】内存泄漏(含泄漏场景、避免方案、检测方法),垃圾回收 GC (含引用计数、标记清除、标记整理、分代式垃圾回收)

内存泄漏 在执行一个长期运行的应用程序时&#xff0c;应用程序分配的内存没有被释放&#xff0c;导致可用内存逐渐减少&#xff0c;最终可能导致浏览器崩溃或者应用性能严重下降的情况&#xff0c;即 JS 内存泄漏 可能导致内存泄漏的场景 不断创建全局变量未及时清理的闭包&…

Graylog 收集网络设备日志的详细配置指南

需求:网络日志接入到日志服务中,做日志的备份和查询。 交换机或是其它网络设备日志需要接入到graylog日志服务中进行备份和查询。 软件版本 graylog5.1 架构图 一、添加inputs 接受日志信息 二、编辑inputs 配置 第1个红框 title 代表通道的名称,您可以根据需要自由定义…

【CTF-Crypto】格密码基础(例题较多,非常适合入门!)

格密码相关 文章目录 格密码相关格密码基本概念&#xff08;属于后量子密码&#xff09;基础的格运算&#xff08;行列式运算&#xff09;SVP&#xff08;shortest Vector Problem&#xff09;最短向量问题CVP&#xff08;Closet Vector Problem&#xff09;最近向量问题 做题要…

浏览器用户文件夹详解 - ShortCuts(六)

1. Shortcuts简介 1.1 什么是Shortcuts文件&#xff1f; Shortcuts文件是Chromium浏览器中用于存储用户创建的快捷方式信息的一个重要文件。每当用户在浏览器中创建快捷方式时&#xff0c;这些信息都会被记录在Shortcuts文件中。通过这些记录&#xff0c;用户可以方便地快速访…

《小迪安全》学习笔记02

域名默认存放目录和IP默认存放目录不一样。 IP地址是WWW文件里的&#xff0c;域名访问是WWW里的一个子目录里的&#xff08;比如是blog&#xff09;。 Nmap: Web源码拓展 拿到一个网站的源码&#xff0c;要分析这几个方面↑。 不同类型产生的漏洞类型也不一样 在网站中&…

MSPM0G3507_2024电赛自动行驶小车(H题)_问题与感悟

这次电赛题目选的简单了&#xff0c;还规定不能使用到摄像头&#xff0c;这让我之前学习的Opencv 4与树莓派无用武之地了&#xff0c;但我当时对于三子棋题目饶有兴趣&#xff0c;但架不住队友想稳奖&#xff0c;只能选择这个H题了...... 之后我还想抽空将这个E题三子棋题目做…

快手批量取关

目录 突然发现快手木有批量取关功能&#xff0c;没有功能就创造功能 执行代码中 逐渐变少 后面关注列表没人了&#xff0c;总数还有32&#xff0c;不知道是不是帮测出个bug还是咋的(^_^) 突然发现快手木有批量取关功能&#xff0c;没有功能就创造功能 刚开始1000多人 执行代…

中间件之异步通讯组件rocketmq入门

一、概述 1.1介绍 RocketMQ是阿里巴巴2016年MQ中间件&#xff0c;使用Java语言开发&#xff0c;RocketMQ 是一款开源的分布式消息系统&#xff0c;基于高可用分布式集群技术&#xff0c;提供低延时的、高可靠的消息发布与订阅服务。同时&#xff0c;广泛应用于多个领域&#…

暖水袋 亚马逊日本站认证 PSE认证步骤

暖水袋是用来加热取暖的生活用品&#xff0c;有内置热水来加热的类型和利用微波炉加热后使用的类型等。内置热水的暖水袋有塑料制、橡胶制、陶器制等多种类型&#xff0c;但是利用加热石头而不是利用热水来取暖的产品类型为审查对象外商品。 审查资料 每个 ASIN 的文件&#x…

成为AI产品经理,为何应选择LLMs方向?

前言 随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;越来越多的人开始考虑如何在这个领域找到自己的位置。对于那些希望成为AI产品经理的人来说&#xff0c;选择LLMs&#xff08;Large Language Models&#xff0c;大型语言模型&#xff09;方向是一个非常…

mac下通过brew安装mysql的环境调试

mac安装mysql 打开终端&#xff0c;运行命令&#xff08;必须已经装过homebrew哦&#xff09;&#xff1a; 安装brewbin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"已安装brew直接运行&#xff1a;brew install mysql8.0报…

模拟自然光照:饮料稳定性测试的创新方法

饮料添加剂的光照稳定性测试旨在评估其在光照影响下的保持稳定性的能力&#xff0c;特别是在储存期间。此测试有助于制造商理解饮料在不同光源作用下的变化&#xff0c;例如颜色、口感、香气等感官性质的变化&#xff0c;以及营养成分的衰变速率。这些信息对改进产品配方、包装…

泉盛UV-K5/K6固件编译教程

0.准备的硬件 win11/win10电脑泉盛UV-K5/K6k口写频线 1.准备的文件&#xff08;点击链接下载&#xff09; gcc arm编译器 链接: gcc-arm-none-eabi-10.3-2021.10-win32Make 链接:Download make-3.81.exe (GnuWin) 2.编译过程&#xff08;这里以Losehu固件为例子&#xff09; 0.…

AI时代的职场焦虑与机遇

原文链接&#xff1a;https://tecdat.cn/?p37205 在人工智能的浪潮中&#xff0c;职场焦虑愈发显著。本杰明米勒的故事便是这一现象的缩影。2023年初&#xff0c;他领导着一个超过60人的团队&#xff0c;为一家科技公司创作推广文章和博客。然而&#xff0c;随着公司决定采用…

排序算法:插入排序,golang实现

目录 前言 插入排序 代码示例 1. 算法包 2. 插入排序代码 3. 模拟程序 4. 运行程序 5. 从大到小排序 插入排序的思想 循环细节 外层循环 内层循环 循环次数测试 假如 10 条数据进行排序 假如 20 条数据进行排序 假如 30 条数据进行排序 假设 5000 条数据&…

Elasticsearch服务器开发教程(第2版 电子版)

前言 本书也将讨论被称为Querydsl的查询语言&#xff0c;通过它可以创建复杂的查询并过滤返回的结果。除了这些&#xff0c;你还将看到如何使用切面技术&#xff08;faceting&#xff09;基于查询结果来计算汇总数据&#xff0c;以及如何使用新引进的聚合框架&#xff08;分析…

云计算 Logstash 配置管理 Kibana数据统计分析

日志分析系统ELK 项目架构图 Logstash 是一个开源的、服务器端的数据收集引擎&#xff0c;与 Elasticsearch 和 Kibana 一起构成了 Elastic Stack&#xff08;之前称为 ELK Stack&#xff09;。Logstash 的主要功能是处理和转发数据&#xff0c;它可以从多种数据源收集数据&a…

Autowired自动注入Map问题

问题 昨天开发的时候遇到一个诡异的问题&#xff0c;通过Map注入接口下所有的子类&#xff0c;然后json打印出来的时候&#xff0c;没有子类的信息&#xff0c;并且去调用的时候报了空指针异常。 排查问题过长&#xff0c;并且涉及到源码&#xff0c;所以这里先说结论&#x…