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

相关文章

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

一文详解Nginx的强缓存和协商缓存

《一文详解Nginx的强缓存和协商缓存》这篇文章主要为大家详细介绍了Nginx中强缓存和协商缓存的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、强缓存(Strong Cache)1. 定义2. 响应头3. Nginx 配置示例4. 行为5. 适用场景二、协商缓存(协

Golang基于内存的键值存储缓存库go-cache

《Golang基于内存的键值存储缓存库go-cache》go-cache是一个内存中的key:valuestore/cache库,适用于单机应用程序,本文主要介绍了Golang基于内存的键值存储缓存库... 目录文档安装方法示例1示例2使用注意点优点缺点go-cache 和 Redis 缓存对比1)功能特性

MySQL8.0设置redo缓存大小的实现

《MySQL8.0设置redo缓存大小的实现》本文主要在MySQL8.0.30及之后版本中使用innodb_redo_log_capacity参数在线更改redo缓存文件大小,下面就来介绍一下,具有一... mysql 8.0.30及之后版本可以使用innodb_redo_log_capacity参数来更改

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

MySQL 缓存机制与架构解析(最新推荐)

《MySQL缓存机制与架构解析(最新推荐)》本文详细介绍了MySQL的缓存机制和整体架构,包括一级缓存(InnoDBBufferPool)和二级缓存(QueryCache),文章还探讨了SQL... 目录一、mysql缓存机制概述二、MySQL整体架构三、SQL查询执行全流程四、MySQL 8.0为何移除查

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

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

Redis与缓存解读

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

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

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