22. Hibernate 性能之缓存

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: selectstudent0_.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_ fromStudent student0_ wherestudent0_.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: selectstudent0_.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_ fromStudent student0_ wherestudent0_.stuId=?
Hibernate
--------------第二次查询------------------
Hibernate: selectstudent0_.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_ fromStudent student0_ wherestudent0_.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: selectstudent0_.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_ fromStudent student0_ wherestudent0_.stuId=?
学生姓名:Hibernate
--------------第二次查询------------------
学生姓名:Hibernate

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

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

5. 小结

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

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

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

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

相关文章

html+css 实现遮罩按钮

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽效果&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 文…

使用obsidian-webpage-export 插件,将 Obsidian 中的笔记导出为网页

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…

快速排序(上)

快速排序 前言 快速排序算法是最流行的排序算法,且有充足的理由,因为在大多数情况下,快速排序都是最快的。所以学习快速排序算法十分有必要。当然&#xff0c;既然它这么好&#xff0c;也就不太容易理解。 正文 Hoare版快排 快速排序是Hoare在1962年提出的一种二叉树结构的…

数字图像边缘曲率计算及特殊点检测

一、曲率和数字图像边缘曲率检测常用方法简介 边缘曲率作为图像边缘特征的重要参数&#xff0c;不仅反映了边缘的几何形状信息&#xff0c;还对于图像识别、图像分割、目标跟踪等任务具有显著影响。 曲线的曲率&#xff08;curvature&#xff09;就是针对曲线上某个点的切线方向…

如何对同一个项目,不同分支,开两个IDEA窗口?

问题&#xff1a;有次我想参考&#xff08;fu zhi&#xff09;某个分支的代码&#xff0c;来写代码&#xff0c;但是打开双击项目的pom文件&#xff0c;会自动打开现在的IDEA窗口&#xff0c;如下&#xff1a; 解决&#xff1a;后面我用Open的方式打开&#xff0c;也是一样的。…

【C语言版】数据结构教程(一)绪论(上)

【内容简介】本文整理数据结构&#xff08;C语言版&#xff09;相关内容的复习笔记&#xff0c;供各位朋友借鉴学习。本章内容更偏于记忆和理解&#xff0c;请读者们耐心阅读。 数据结构教程 绪论&#xff08;上&#xff09; 本节学习目标 1.1 基本概念 1.2 抽象数据类型的表示…

RAG 革命:NVIDIA 工作站如何成为企业 AI 的秘密武器

在深圳的一家科技初创公司&#xff0c;首席技术官李梅正在向她的团队展示一个令人兴奋的新项目。“看这个&#xff0c;” 她指着屏幕上的实时演示说&#xff0c;“我们刚刚用公司的技术文档训练了一个 AI 助手&#xff0c;它现在可以回答任何关于我们产品的问题&#xff0c;而且…

C 语言快速排序算法

升序排序 /*快速排序算法排序规则 */ int32_t CmpCb(const void* _a, const void* _b) {uint16_t* a (uint16_t*)_a;uint16_t* b (uint16_t*)_b;int32_t val 0;if (*a > *b){val 1;}else if (*a < *b){val -1;}else {val 0;}return val; }int main() {// 创建局部…

亚马逊爬虫(Amazonbot)IP地址,真实采集数据

一、数据来源&#xff1a; 1、这批亚马逊爬虫&#xff08;Amazonbot&#xff09;IP来源于尚贤达猎头公司网站采集数据&#xff1b; ​ 2、数据采集时间段&#xff1a;2023年10月-2024年7月&#xff1b; 3、判断标准&#xff1a;主要根据用户代理是否包含“Amazonbot”和IP核…

Simulink|基于粒子群算法的永磁同步电机多参数辨识

目录 主要内容 模型研究 结果一览 下载链接 主要内容 仿真程序参考文献《改进粒子群算法的永磁同步电机多参数辨识》&#xff0c;采用粒子群算法与simulink模型结合的方式&#xff0c;对永磁同步电机进行多参数辨识。程序以定子绕组电阻、d轴电感、q轴电感和永磁…

吴恩达老师机器学习-ex3

使用逻辑回归 导入库&#xff0c;因为这次的数据是mat文件&#xff0c;需要使用scipy库中的loadmat进行读取数据。 通过对数据类型的分析&#xff0c;发现是字典类型&#xff0c;查看该字典的键&#xff0c;可以发现又X&#xff0c;y等关键字。 import numpy as np import m…

memos content too long

搜到 issue 已经支持 https://github.com/usememos/memos/issues/3262 实际配置在页面上下面路径

排序算法:堆排序,golang实现

目录 前言 堆排序 代码示例 1. 算法包 2. 堆排序代码 3. 模拟程序 4. 运行程序 5. 从大到小排序 堆排序的思想 堆排序的实现逻辑 1. 构建最大堆 2. 排序 循环次数测试 假如 10 条数据进行排序 假如 20 条数据进行排序 假如 30 条数据进行排序 假设 5000 条数据…

C# 串口控制 校验

1. 串口控制 using System; using System.IO.Ports; using System.Windows.Forms;namespace 串口控制 {public partial class Form1 : Form{//device1const byte DeviceOpen1 0x01;const byte DeviceClose1 0x81;//device2const byte DeviceOpen2 0x02;const byte DeviceCl…

git 、shell脚本

git 文件版本控制 安装git yum -y install git 创建仓库 将文件提交到暂存 git add . #将暂存区域的文件提交仓库 git commit -m "说明" #推送到远程仓库 git push #获取远程仓库的更新 git pull #克隆远程仓库 git clone #分支&#xff0c;提高代码的灵活性 #检查分…

【C++进阶学习】第十一弹——C++11(上)——右值引用和移动语义

前言&#xff1a; 前面我们已经将C的重点语法讲的大差不差了&#xff0c;但是在C11版本之后&#xff0c;又出来了很多新的语法&#xff0c;其中有一些作用还是非常大的&#xff0c;今天我们就先来学习其中一个很重要的点——右值引用以及它所扩展的移动定义 目录 一、左值引用和…

step:菜单栏静态加载和动态加载

文章目录 文章介绍静态加载动态加载补充材料 文章介绍 对比静态加载和动态加载。 主界面main.qml之前使用的是动态加载&#xff0c;动态加载导致的问题&#xff1a;菜单栏选择界面切换时&#xff0c;之前的界面内容被清空。 修改方法&#xff1a;将动态加载改为静态加载 左边是…

九大原则,轻松构建个人高效SOP

1、原则一、工作汇报SOP SCQA模型(升职加薪的关键!&#xff09; 清晰定义问题和提出解决方案 类别 关键词 解读 S - Situation 情景 陈述项目背景&#xff0c;目标&#xff0c;愿景 C - Complication 冲突 讲卡点&#xff0c;讲冲突 Q - Question 疑问-问题 这些冲…

MyBatis基础配置

一、M y B a t i s 配 置 文 件 MyBatis配置文件的功能&#xff1a;构建SqlSessionFactory的依据 MyBatis配置文件的意义&#xff1a;MyBatis最为核心的内容&#xff0c;对MyBatis的使用影响很大。 MyBatis配置文件注意事项&#xff1a;配置文件的层次顺序不能颠倒&#xff0c;…

镜像制作和管理

文章目录 一、Docker镜像说明Docker镜像中没有内核为什么没有内核容器中的程序后台运行会导致此容器启动后立即退出镜像的生命周期和制作方式 二、手动构建镜像基于容器手动制作镜像步骤实际操作基于 busybox 制作httpd镜像制作tomcat镜像基于ubuntu的基础镜像手动安装nginx镜像…