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

相关文章

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Java实现本地缓存的常用方案介绍

《Java实现本地缓存的常用方案介绍》本地缓存的代表技术主要有HashMap,GuavaCache,Caffeine和Encahche,这篇文章主要来和大家聊聊java利用这些技术分别实现本地缓存的方... 目录本地缓存实现方式HashMapConcurrentHashMapGuava CacheCaffe

如何更改pycharm缓存路径和虚拟内存分页文件位置(c盘爆红)

《如何更改pycharm缓存路径和虚拟内存分页文件位置(c盘爆红)》:本文主要介绍如何更改pycharm缓存路径和虚拟内存分页文件位置(c盘爆红)问题,具有很好的参考价值,希望对大家有所帮助,如有... 目录先在你打算存放的地方建四个文件夹更改这四个路径就可以修改默认虚拟内存分页js文件的位置接下来从高级-

PyCharm如何更改缓存位置

《PyCharm如何更改缓存位置》:本文主要介绍PyCharm如何更改缓存位置的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录PyCharm更改缓存位置1.打开PyCharm的安装编程目录2.将config、sjsystem、plugins和log的路径

JSR-107缓存规范介绍

《JSR-107缓存规范介绍》JSR是JavaSpecificationRequests的缩写,意思是Java规范提案,下面给大家介绍JSR-107缓存规范的相关知识,感兴趣的朋友一起看看吧... 目录1.什么是jsR-1072.应用调用缓存图示3.JSR-107规范使用4.Spring 缓存机制缓存是每一

Spring 缓存在项目中的使用详解

《Spring缓存在项目中的使用详解》Spring缓存机制,Cache接口为缓存的组件规范定义,包扩缓存的各种操作(添加缓存、删除缓存、修改缓存等),本文给大家介绍Spring缓存在项目中的使用... 目录1.Spring 缓存机制介绍2.Spring 缓存用到的概念Ⅰ.两个接口Ⅱ.三个注解(方法层次)Ⅲ.

Spring Boot 整合 Redis 实现数据缓存案例详解

《SpringBoot整合Redis实现数据缓存案例详解》Springboot缓存,默认使用的是ConcurrentMap的方式来实现的,然而我们在项目中并不会这么使用,本文介绍SpringB... 目录1.添加 Maven 依赖2.配置Redis属性3.创建 redisCacheManager4.使用Sp

springboot项目redis缓存异常实战案例详解(提供解决方案)

《springboot项目redis缓存异常实战案例详解(提供解决方案)》redis基本上是高并发场景上会用到的一个高性能的key-value数据库,属于nosql类型,一般用作于缓存,一般是结合数据... 目录缓存异常实践案例缓存穿透问题缓存击穿问题(其中也解决了穿透问题)完整代码缓存异常实践案例Red

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示