hibernate缓存学习之【一级缓存】

2024-08-25 14:48
文章标签 学习 缓存 hibernate 一级

本文主要是介绍hibernate缓存学习之【一级缓存】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        最先接触到缓存机制是在学习计算机操作系统原理时,计算机的缓存机制是为了解决CPU和内存的速度差异。CPU存取数据的速度非常快,相对CPU来说内存的速度就慢很多。CPU需要从内存中读取一些数据但是由于内存的速度慢就无法及时提供,所以内存中使用最频繁的数据、指令会被复制到CPU的缓存中CPU就不需要总是和内存打交道这样可以提高效率。CPU的缓存也分为一级和二级,在实际访问中会先找一级缓存,一级没有就会找二级缓存如果二级缓存中也没有就只能到内存中查找。详细原理小编还需要进一步了解。

对比操作系统的缓存机制我们会发现hibernate的缓存机制大体上和操作系统是一致的。

Why:

       为什么hibernate会出现缓存机制?因为hibernate是属于持久层的所以会频繁的和数据库打交道进行数据的读取,正如CPU需要从内存中读取数据类似。为了减少程序运行时访问物理数据源的次数提高运行程序的性能所以hibernate出现了缓存机制,这样hibernate在进行数据读取时会先从一级缓存中查找如果没有则查找二级缓存如果还没有就会访问数据库。和CPU缓存机制类型hibernate缓存中的数据也会根据特定机制进行更新。

What:

hibernate的缓存也分为一级和二级

       一级缓存也称Session级缓存——

           1、  使用session控制,生命周期同session;所以当前session关闭后,缓存就没了

           2、  只能在当前线程中使用,不同的session间不能共享缓存数据

      二级缓存也称sessionFactory级缓存或进程级缓存——

           1、  使用sessionFactory控制,生命周期同sessionFactory

           2、  在当前进程中使用

       共同特点:只缓存实体对象,如果使用HQL查询普通属性不会缓存。具体的意思可以从实例中体会。

How:

         首先是一级缓存的使用:可分为查询实体和查询个别属性

         查询实体:

                   load或get查询一个实体:               

    /*** 在同一个session中发出两次load查询*/public void testLoad() {Sessionsession = null;try {session= HibernateUtils.getSession();session.beginTransaction();Studentstudent = (Student)session.load(Student.class, 1);System.out.println("student.name="+ student.getName());//不会发出查询语句,load使用缓存student= (Student)session.load(Student.class, 1);System.out.println("student.name="+ student.getName());session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}}    

         执行完毕发现只发出一条查询语句,说明在第二次进行查询时session是从自己的缓存中获取的数据而不是从库中获取的。测试get方法和load方法是一样的。load和get方法的区别在于load默认是支持延迟加载的。


         list或iterate查询实体集:

   /*** 在同一个session中发出两次iterate查询,查询实体对象*/public void testIterate () {Sessionsession = null;try {session= HibernateUtils.getSession();session.beginTransaction();Iteratoriter = session.createQuery("from Student swhere s.id<5").iterate();while (iter.hasNext()) {Studentstudent = (Student)iter.next();System.out.println(student.getName());}System.out.println("--------------------------------------");//它会发出查询id的语句,但不会发出根据id查询学生的语句,因为iterate使用缓存iter= session.createQuery("from Student swhere s.id<5").iterate();while (iter.hasNext()) {Studentstudent = (Student)iter.next();System.out.println(student.getName());}session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}} </span>
执行结果如下:


     

        第一次查询时iterate会发出1条查询所有id的语句,然后在打印student的name时发出n条根据id查询详细信息的语句一共N+1条。而第二次查询时只发出一条查询id的语句,其他的数据是从session的缓存中获取的。


使用list在同意session中查询实体集,发出的查询语句如下:会发出两条查询语句

      

        出现如上的结果是不是说明使用iterate查询的结果才会放到session的缓存中而list的结果不会放到缓存中呢?看下面一个实例

   /*** 在同意session中先使用list,然后使用iterate进行查询*/public void testListIterate () {Sessionsession = null;try {session= HibernateUtils.getSession();session.beginTransaction();Liststudents = session.createQuery("select s fromStudent s where s.id<5").list();for (int i=0;i<students.size(); i++) {Studentstudnet = (Student)students.get(i);System.out.println(studnet.getName());}System.out.println("----------------------------------");Iteratoriter = session.createQuery("from Student swhere s.id<5").iterate();while (iter.hasNext()) {Studentstudent = (Student)iter.next();System.out.println(student.getName());}session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}}    </span>

打印出的查询语句如下:

       

        上图中我们看到在使用iterate进程查询时没有发出N+1条语句,只发出了查询所有id的语句,结合两个例子说明list查出的结果会放到session的缓存中但是list本身的查询不会直接使用缓存中的数据,还是在此查询数据库。

 

查询普通属性:

       使用iterate查询某个普通属性,代码实例如下——

   /*** 在同一个session中发出两次iterate查询,查询普通属性*/public void testCache4() {Sessionsession = null;try {session= HibernateUtils.getSession();session.beginTransaction();Iteratoriter = session.createQuery("select s.namefrom Student s where s.id<5").iterate();while (iter.hasNext()) {Stringname = (String)iter.next();System.out.println(name);}System.out.println("--------------------------------------");//iterate查询普通属性,一级缓存不会缓存,所以发出查询语句//一级缓存是缓存实体对象的iter= session.createQuery("select s.namefrom Student s where s.id<5").iterate();while (iter.hasNext()) {Stringname = (String)iter.next();System.out.println(name);}session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}}    

       以上代码执行观察结果发现会发出两条查询语句,这说明只查询普通属性时session是不会进行缓存的。


一级缓存的生命周期:

/*** 在两个session中发load查询*/public void testCache5() {Sessionsession = null;try {session= HibernateUtils.getSession();session.beginTransaction();Studentstudent = (Student)session.load(Student.class, 1);System.out.println("student.name="+ student.getName());session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}try {session= HibernateUtils.getSession();session.beginTransaction();Studentstudent = (Student)session.load(Student.class, 1);//会发出查询语句,session间不能共享一级缓存数据//因为他会伴随着session的消亡而消亡System.out.println("student.name="+ student.getName());session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}
}    

执行打印出的查询语句如下:

       

        发出两条查询语句和在第一个测试中使用同一个session只发一条查询语句是有差别的,这说明了一级缓存的生命周期是和session一致的,session关闭缓存就会消失。

 

小结:

         本篇博客介绍了通过操作系统的缓存机制映射到hibernate的缓存机制,发现它俩的思想是一样的。

         通过几个实例发现get/load/iterate/list在查询实体时都是支持一级缓存的,而且一级缓存的生命周期和session是一致的,当session关闭当前session中的缓存就会消失。下篇博客通过几个代码实例分析一下二级缓存及一级和二级缓存之间的关系。

这篇关于hibernate缓存学习之【一级缓存】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1105856

相关文章

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

Redis与缓存解读

《Redis与缓存解读》文章介绍了Redis作为缓存层的优势和缺点,并分析了六种缓存更新策略,包括超时剔除、先删缓存再更新数据库、旁路缓存、先更新数据库再删缓存、先更新数据库再更新缓存、读写穿透和异步... 目录缓存缓存优缺点缓存更新策略超时剔除先删缓存再更新数据库旁路缓存(先更新数据库,再删缓存)先更新数

el-select下拉选择缓存的实现

《el-select下拉选择缓存的实现》本文主要介绍了在使用el-select实现下拉选择缓存时遇到的问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录项目场景:问题描述解决方案:项目场景:从左侧列表中选取字段填入右侧下拉多选框,用户可以对右侧

SpringBoot使用注解集成Redis缓存的示例代码

《SpringBoot使用注解集成Redis缓存的示例代码》:本文主要介绍在SpringBoot中使用注解集成Redis缓存的步骤,包括添加依赖、创建相关配置类、需要缓存数据的类(Tes... 目录一、创建 Caching 配置类二、创建需要缓存数据的类三、测试方法Spring Boot 熟悉后,集成一个外

使用Spring Cache时设置缓存键的注意事项详解

《使用SpringCache时设置缓存键的注意事项详解》在现代的Web应用中,缓存是提高系统性能和响应速度的重要手段之一,Spring框架提供了强大的缓存支持,通过​​@Cacheable​​、​​... 目录引言1. 缓存键的基本概念2. 默认缓存键生成器3. 自定义缓存键3.1 使用​​@Cacheab

Nacos客户端本地缓存和故障转移方式

《Nacos客户端本地缓存和故障转移方式》Nacos客户端在从Server获得服务时,若出现故障,会通过ServiceInfoHolder和FailoverReactor进行故障转移,ServiceI... 目录1. ServiceInfoHolder本地缓存目录2. FailoverReactorinit

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;