Hibernate二级缓存的使用

2024-06-08 00:48

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

一、Hibernate 共有两级缓存

         Session级别缓存 ---- 一级缓存(事务范围)

         SessionFactory 级别缓存 ---- 二级缓存(进程范围)

 

SessionFactory级别缓存

         内置:Hibernate 自带的, 不可卸载. 通常在 Hibernate 的初始化阶段, Hibernate 会把映射元数据和预定义的 SQL 语句放到 SessionFactory 的缓存中, 映射元数据是映射文件中数据的复制,而预定义 SQL 语句时 Hibernate 根据映射元数据推到出来的. 该内置缓存是只读的.

         外置:需要去配置第三方缓存插件(hibernate内部没有二级缓存实现),在默认情况下, SessionFactory不会启用这个缓存插件. 外置缓存中的数据是数据库数据的复制, 外置缓存的物理介质可以是内存或硬盘

        

二级缓存结构

         二级缓存包含 :类级别缓冲区、集合级别缓存区、更新时间戳缓冲区、查询缓存

                   注:有些人将查询缓存 称为是Hibernate 第三级缓存 ,查询缓存依赖于二级缓存,比二级缓存功能更加强大。

二级缓存的并发策略

         为了便于记忆,理解二级缓存 事务并发策略对应 事务隔离级别

         非严格读写(Nonstrict-read-write)

         读写型(Read-write)(用的最多)

         事务型(Transactional)

         只读型(Read-Only) 

适用二级缓存

         二级缓存适用于很少被修改的数据或者不是很重要的数据, 允许出现偶尔的并发问题。我们可以通过缓      存性能监控(通过适用次数判断),测试是否应该使用二级缓存

二级缓存支持四种 : EHCache 、OSCache 、 SwarmCache 和 JBossCache

                   * 本地数据库使用 EHCache 、OSCache

                   * 分布式数据库使用(企业) SwarmCache 和 JBossCache (支持集群范围缓存)

         EHCache:可作为进程范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 对Hibernate的查询缓 存提供了支持

         OpenSymphony:可作为进程范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 提供了丰富的缓存数据过期策略, 对Hibernate的查询缓存提供了支持

         SwarmCache: 可作为集群范围内的缓存, 但不支持 Hibernate 的查询缓存

         JBossCache:可作为集群范围内的缓存, 支持 Hibernate 的查询缓存

缓存插件支持的并发访问策略


二级缓存快速入门

         1)导入jar包 hibernate 每个版本jar包中自带相关二级缓存jar包

                   ehcache除了需要导入自己的jar包,还需要依赖backport-util-concurrent 和 commons-logging

          

         2)在hibernate.cfg.xml开启二级缓存

                   <property name="hibernate.cache.use_second_level_cache">true</property>

         3)配置二级缓存提供商

                   <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

         4)配置二级缓存并发策略

                   方法一:在 hbm 映射文件中配置

                   <classname="cn.itcast.query.Customer" table="customer"catalog="hibernate3day4" >

                            <cacheusage="read-write"/>

                   方法二:在hibernate.cfg.xml 文件中配置  

                   <class-cacheusage="read-write" class="cn.itcast.query.Customer"/>类级别的缓存

                   <class-cacheusage="read-write" class="cn.itcast.query.Order"/>类级别的缓存

                   <collection-cacheusage="read-write" collection="cn.itcast.query.Customer.orders"/>集合级别的缓存

         5)配置二级缓存的核心配置文件ehcache.xml

                   将ehcache.jar中ehcache-failsafe.xml 改名为ehcache.xml后复制到src就可以了。

        

二级缓存操作

案例一 : 证明二级缓存是存在的与类级别缓冲区的散装数据结构    

         对于一级缓存来说存储的是对象的地址,而地址引用的是内存中的实体类。

         对于二级缓存来说存储的是对象的属性散装数据(存在其类级别缓冲区中)。当要获取二级缓存中的数 据的时候,他会根据这些数据(id、name)重新组装成为一个对象(customer)。

         <class-cacheusage="read-write" class="cn.itcast.query.Customer"/>


	例:// 测试二级缓存是存在的 、类级别缓存数据是散装数据结果public void demo1() {Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();// 查询结果 会被 保存一级缓存 ,当开启二级缓存后,也会保存到二级缓存Customer customer1 = (Customer) session.get(Customer.class, 1);System.out.println(customer1);// 当再次查询的时候,因为一级缓存是存在,就从一级缓存直接获得Customer customer2 = (Customer) session.get(Customer.class, 1);System.out.println(customer2);//由于获得当前线程绑定的session,所以就不需要关闭Session,当session关闭后,一级缓存清空。transaction.commit();		//当再次需要数据的时候,获得当前线程绑定的session,再次开启事务session = HibernateUtils.getCurrentSession();transaction = session.beginTransaction();// 不会产生SQL ,因为数据 可以从二级缓存找到Customer customer3 = (Customer) session.get(Customer.class, 1);System.out.println(customer3);transaction.commit();}案例二 : 测试 get/load 可以读取二级缓存数据, Query的list方法 只能存,不能取
例:@Test// 测试Query的list方法只能向二级缓存保存数据,不能读取二级缓存public void demo2() {Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();// Query的list 会将查询结果 存入二级缓存List<Customer> customers = session.createQuery("from Customer").list();System.out.println(customers);transaction.commit(); // session 关闭,一级缓存清空session = HibernateUtils.getCurrentSession();transaction = session.beginTransaction();// Query 的list 不会读取二级缓存List<Customer> customers2 = session.createQuery("from Customer").list();System.out.println(customers2);transaction.commit();session = HibernateUtils.getCurrentSession();transaction = session.beginTransaction();// 不会产生SQL ,因为Query 已经将数据保存到二级缓存,get/load可以读取二级缓存Customer customer = (Customer) session.get(Customer.class, 1);System.out.println(customer);transaction.commit();}案例三 : 集合级别缓存区存储原理 (只会缓存OID ,数据保存类级别缓冲区中 )<collection-cache usage="read-write" collection="cn.itcast.query.Customer.orders"/>
例:public void demo3() {Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();//查询客户,将其存入类级别的缓存Customer customer = (Customer) session.get(Customer.class, 1);System.out.println(customer.getOrders().size()); //这里查询了订单集合,也会将散装数据保存到二级缓存,另外将id缓存到集合级别缓冲区。for (Order order : customer.getOrders()) {System.out.println(order.getAddress());}transaction.commit();session = HibernateUtils.getCurrentSession();transaction = session.beginTransaction();Customer customer2 = (Customer) session.get(Customer.class, 1);// 这里再次查询order就不会产生新的SQL语句,他会根据在集合级别缓冲区的id对比后,到类级别			缓冲区找到散装的数据进行组合System.out.println(customer2.getOrders().size());for (Order order : customer.getOrders()) {System.out.println(order.getAddress());}transaction.commit();
如果将hibernate.cfg.xml中<class-cache usage="read-write" class="cn.itcast.query.Order"/> 注释掉,会产生额外10条SQL,原因是order的类级别缓存区缓存不了数据了,再次根据id到类级别缓冲区查找数据就没有了。才会去编写sql进行查询}
案例四 :一级缓存更新会同步到二级缓存 
例:@Testpublic void demo4() {Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();// 数据放入一级缓存和二级缓存Customer customer = (Customer) session.get(Customer.class, 1); System.out.println(customer);//修改一级缓存数据customer.setCity("石家庄"); // 一级缓存同步到二级缓存transaction.commit(); session = HibernateUtils.getCurrentSession();transaction = session.beginTransaction();// 查询的是修改后的数据Customer customer2 = (Customer) session.get(Customer.class, 1);System.out.println(customer2);//city为石家庄transaction.commit();}
案例五 :关于将二级缓存数据保存到硬盘上 当缓存的数据特别多的时候就需要将数据缓存到硬盘上,在ehcache.xml中通过配置<diskStore path="java.io.tmpdir"/> 指定缓存数据硬盘的位置。// 打印临时文件目录public void demo5() {//获取实际路径方法:java.io.tmpdir 是 keySystem.out.println(System.getProperty("java.io.tmpdir"));}

         将 C:\ehcache 配置临时文件存放目录 (建议win7 同学们不要用c 盘目录)

         ehcache.xml 提供  <defaultCache> 是二级缓存默认配置 (对所有缓存都有效)

                   通过 <cache name="cn.itcast.query.Customer" > 该配置只对Customer 缓存有效

          <defaultCache

           maxElementsInMemory="10000" 内存中最大元素数量(当内存中的对象数量超过这个数,才会缓存到硬盘)

            eternal="false"  缓存数据是否永久有效

            timeToIdleSeconds="120" 设置对象空闲最长时间 ,超过时间缓存对象如果没用,就会回收

           timeToLiveSeconds="120" 设置对象存活最长时间, 无论对象是否使用,到时间就会回收

           overflowToDisk="true"  当内存缓存数据达到上限,是否缓存到硬盘

           maxElementsOnDisk="10000000"  硬盘上最大缓存对象数量

           diskPersistent="false"  当jvm结束时是否持久化对象 truefalse 默认是false

           diskExpiryThreadIntervalSeconds="120" 专门用于清除过期对象的监听线程的轮询时

           memoryStoreEvictionPolicy="LRU"

     />


案例六: 测试更新时间戳缓存区域 
例:public void demo7() {Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();// 查询customer信息,放入二级缓存,并且记录了时间为t1Customer customer = (Customer) session.get(Customer.class, 1); System.out.println(customer);// 这样修改数据库数据是不行的,因为修改一级缓存 自动同步 二级缓存// customer.setCity("济南"); //如果这样改就不通过缓存了,并且记录时间为t2
		session.createQuery("update Customer set city='济南' where id = 1").executeUpdate(); transaction.commit();session = HibernateUtils.getCurrentSession();transaction = session.beginTransaction();//比较 t2 > t1,若果 修改时间在缓存时间之后,证明数据被修改了,就会 重新生成SQL进行查询Customer customer2 = (Customer) session.get(Customer.class, 1);System.out.println(customer2);transaction.commit();}

Query 接口的iterate 方法

         当获得iterator 迭代器时,返回代理对象,当中数据只有OID

         在访问每个元素时,优先查找二级缓存,如果找不到,生成SQL 语句

例:public void demo8() {Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();// 查询前10条订单,放入二级缓存List<Order> orders = session.createQuery("from Order where id < 11").list();transaction.commit();session = HibernateUtils.getCurrentSession();transaction = session.beginTransaction();// 查询前15条订单,只会查询小于16的OID 返回代理对象
		Iterator<Order> iterator = session.createQuery("from Order where id < 16").iterate();  // 前十个订单,来自二级缓存,不会生成SQLwhile (iterator.hasNext()) {System.out.println(iterator.next().getAddress());}transaction.commit();}

 

查询缓存操作

查询缓存和二级缓存关系 

         查询缓存是对二级缓存 进一步增强,可以缓存任何查询语句的结果。

         二级缓存查询结果,比如以OID作为key,以对象作为Value 进行缓存,查询缓存以SQL语句为      key,以查询结果作为Value

使用步骤

1) 配置开启查询缓存在hibernate.cfg.xml

         <property name="hibernate.cache.use_query_cache">true</property> 

                   (注意查询缓存,必须要先开启二级缓存)

2) 在程序中通过Query 的setCacheable(true)开启查询缓存

例:public void demo9() {Session session = HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();// 查询所有客户的姓名,这里没有OID,所以二级缓存做不到这点Query query = session.createQuery("select name from Customer");query.setCacheable(true); // 启用查询缓存List list = query.list(); // 将查询结果 放入了查询缓存System.out.println(list);transaction.commit();session = HibernateUtils.getCurrentSession();transaction = session.beginTransaction();//在查询缓存的取数据的时候也要开启查询缓存query = session.createQuery("select name from Customer");query.setCacheable(true); // 启用查询缓存List list2 = query.list(); // 从查询缓存 获得结果System.out.println(list2);transaction.commit();}

二级缓存的性能检测

         缓存性能的监控主要是通过访问二级缓存的次数来判断二级缓存的效率,测试是否应该使用二级缓存。

步骤:

1、 在hibernate.cfg.xml 将 hibernate.generate_statistics 配置true 启用 性能检测

                   <property name="hibernate.generate_statistics">true</property>

2、 使用SessionFactory 提供方法进行检测

         二级缓存

          sessionFactory.getStatistics().getSecondLevelCacheHitCount(); 二级缓存命中次数

          sessionFactory.getStatistics().getSecondLevelCacheMissCount();二级缓存丢失次数

          hitCount/ (hitCount+missCount) 二级缓存命中率

         查询缓存

         sessionFactory.getStatistics().getQueryCacheHitCount()查询缓存命中次数

         sessionFactory.getStatistics().getQueryCacheMissCount()查询缓存丢失次数

         queryCacheHitCount /(queryCacheHitCount + queryCacheMissCount); 查询缓存命中率




这篇关于Hibernate二级缓存的使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

gitlab安装及邮箱配置和常用使用方式

《gitlab安装及邮箱配置和常用使用方式》:本文主要介绍gitlab安装及邮箱配置和常用使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1.安装GitLab2.配置GitLab邮件服务3.GitLab的账号注册邮箱验证及其分组4.gitlab分支和标签的

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

nginx启动命令和默认配置文件的使用

《nginx启动命令和默认配置文件的使用》:本文主要介绍nginx启动命令和默认配置文件的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录常见命令nginx.conf配置文件location匹配规则图片服务器总结常见命令# 默认配置文件启动./nginx

在Windows上使用qemu安装ubuntu24.04服务器的详细指南

《在Windows上使用qemu安装ubuntu24.04服务器的详细指南》本文介绍了在Windows上使用QEMU安装Ubuntu24.04的全流程:安装QEMU、准备ISO镜像、创建虚拟磁盘、配置... 目录1. 安装QEMU环境2. 准备Ubuntu 24.04镜像3. 启动QEMU安装Ubuntu4

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

Windows下C++使用SQLitede的操作过程

《Windows下C++使用SQLitede的操作过程》本文介绍了Windows下C++使用SQLite的安装配置、CppSQLite库封装优势、核心功能(如数据库连接、事务管理)、跨平台支持及性能优... 目录Windows下C++使用SQLite1、安装2、代码示例CppSQLite:C++轻松操作SQ

Python常用命令提示符使用方法详解

《Python常用命令提示符使用方法详解》在学习python的过程中,我们需要用到命令提示符(CMD)进行环境的配置,:本文主要介绍Python常用命令提示符使用方法的相关资料,文中通过代码介绍的... 目录一、python环境基础命令【Windows】1、检查Python是否安装2、 查看Python的安

Python并行处理实战之如何使用ProcessPoolExecutor加速计算

《Python并行处理实战之如何使用ProcessPoolExecutor加速计算》Python提供了多种并行处理的方式,其中concurrent.futures模块的ProcessPoolExecu... 目录简介完整代码示例代码解释1. 导入必要的模块2. 定义处理函数3. 主函数4. 生成数字列表5.

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删