Hibernate 一级缓存和二级缓存

2024-04-01 15:18

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

一级缓存[Session级别]

一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个session(一定要同一个session)又做了同一个操作,那么hibernate直接从一级缓存中拿,而不会再去连数据库,取数据

  1. 每个事务都有单独的第一级缓存进程范围或集群范围

    缓存被同一个进程或集群范围内的所有事务共享并发访问策略由于每个事务都拥有单独的第一级缓存,不会出现并发问题
    
  2. 处于一级缓存中的对象永远不会过期

    除非应用程序显式清空缓存或者清除特定的对象,必须提供数据过期策略,如基于内存的缓存中的对象的最大数目,允许对象处于缓存中的最长时间,以及允许对象处于缓存中的最长空闲时间物理存储介质内存内存和硬盘。
    
  3. 对象的散装数据首先存放在基于内存的缓存中,当内存中对象的数目达到数据过期策略中指定上限时,就会把其余的对象写入基于硬盘的缓存中。

  4. save、update、saveOrupdate、load、list、iterate、lock会向一级缓存存放数据

  5. Session为应用程序提供了两个管理缓存的方法:

         evict(Object obj):从缓存中清除参数指定的持久化对象。 clear():清空缓存中所有持久化对象。
    

query.list()和query.iterate()

query.list()会一次性查询出所有的对象并且放入一级缓存中

@Testpublic void testQueryList() throws Exception {Session session = HibernateUtils.getSession();Query query = session.createQuery("from Student");//把查询出的所有学生信息放入一级缓存List<Student> list = (List<Student>) query.list();//此时再查询会直接从一级缓存中取Student student = session.get(Student.class,0);}

输出结果

Hibernate: 
selectstudent0_.id as id1_0_,student0_.phone as phone2_0_,student0_.postcode as postcode3_0_,student0_.birth as birth4_0_,student0_.c_id as c_id7_0_,student0_.gender as gender5_0_,student0_.name as name6_0_ 
fromstudent student0_
Hibernate: selectclasses0_.c_id as c_id1_1_0_,classes0_.c_name as c_name2_1_0_ fromclass classes0_ whereclasses0_.c_id=?

query.iterate()会查询出所有对象的id 当要获取某个对象时再去数据库中取

@Testpublic void testIterate() throws Exception {Session session = HibernateUtils.getSession();Query query = session.createQuery("from Student ");//查询出所有student的idIterator<Student> iterate = query.iterate();//当要获取某个student对象时 再去数据库取while (iterate.hasNext()){System.out.println(iterate.next());}}

输出结果

Hibernate: 
selectstudent0_.id as col_0_0_ 
fromstudent student0_
Hibernate: selectstudent0_.id as id1_0_0_,student0_.phone as phone2_0_0_,student0_.postcode as postcode3_0_0_,student0_.birth as birth4_0_0_,student0_.c_id as c_id7_0_0_,student0_.gender as gender5_0_0_,student0_.name as name6_0_0_,classes1_.c_id as c_id1_1_1_,classes1_.c_name as c_name2_1_1_ fromstudent student0_ left outer joinclass classes1_ on student0_.c_id=classes1_.c_id wherestudent0_.id=?
Student{id=0, name='heqianqian', gender='female', birth=2017-04-30, address=Address{postCode='335400', phone='10086'}

如果我们需要在一个session当中要两次查询出很多对象,可以第一次使用List将对象信息放入一级缓存,第二次使用iterate获取所有对象的id 再根据id去一级缓存中获取数据

注意:

一级缓存不需要配置,就可以使用,它本身没有保护机制,所以我们程序员要考虑这个问题,我们可以同 evict 或者 clear来清除session缓存中对象. evict 是清除一个对象,clear是清除所有的sesion缓存对象

② session级缓存中对象的生命周期, 当session关闭后,就自动销毁.

二级缓存[SessionFactory级别]

使用hibernate二级缓存,我们首先需要对其进行配置,配置步骤如下:

1.添加jar包
hibernate并没有提供相应的二级缓存的组件,常用的二级缓存包是EHcache

<!--cache--><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-ehcache</artifactId><version>5.2.10.Final</version></dependency><dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId><version>2.10.2</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency>

2.在hibernate配置文件中开启二级缓存总开关 并且配置ehcache配置文件的位置

 <!-- 开启二级缓存 --><property name="hibernate.cache.use_second_level_cache">true</property><!-- 二级缓存的提供类 在hibernate4.0版本以后我们都是配置这个属性来指定二级缓存的提供类--><property name="hibernate.cache.region.factory_class">org.hibernate.cache.SingletonEhCacheRegionFactory</property><!-- 二级缓存配置文件的位置 --><property name="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</property><!--如果是使用hibernate3的版本的话,那么二级缓存的提供类则要配置成这个:--><property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</property>

3.在ehcache.xml中配置缓存信息

<ehcache><!--指定数据在磁盘中的存储位置--><diskStore path="F:\ehcache"/><!--当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略--><defaultCache
            maxElementsInMemory="1000"maxElementsOnDisk="10000000"eternal="false"overflowToDisk="false"timeToIdleSeconds="120"timeToLiveSeconds="120"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"><!--必选参数1.maxElementsInMemory:在内存中缓存的element的最大数目2.maxElementsOnDisk:在磁盘上缓存的element的最大数目,若是0表示无穷大3.eternal:设定缓存的elements是否永远不过期如果为true,则缓存的数据始终有效如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断4.overflowToDisk:设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上--><!--可选参数1.timeToIdleSeconds:当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大2.timeToLiveSeconds:缓存element的有效生命期,默认是0.,也就是element存活时间无穷大3.diskSpoolBufferSizeMB:设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区4.diskPersistent:在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false5.diskExpiryThreadIntervalSeconds:磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作6.memoryStoreEvictionPolicy:当内存缓存达到最大,有新的element加入的时候,移除缓存中element的策略。默认是LRU(最近最少使用)可选的有LFU(最不常使用)和FIFO(先进先出)-->
</defaultCache>
</ehcache>

4.开启二级缓存

1)使用xml方式

<class name="com.hqq.bean.Student" table="student" schema="hibernate"><!--二级缓存一般设置为只读的 --><cache usage="read-only"/><id name="id" column="id"/><property name="name" column="name"/><property name="gender" column="gender"/><property name="birth" column="birth"/><!--<property name="address" column="address"/>--><component name="address" class="com.hqq.bean.Address"><property name="phone" column="phone"/><property name="postCode" column="postcode"/></component></class>

二级缓存的使用策略一般有这几种:read-only、nonstrict-read-write、read-write、transactional

2)使用注解的方式

@Entity
@Table(name = "student", schema = "hibernate")
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)//表示开启二级缓存,并使用read-only策略
public class Student implements Serializable {

5.配置完毕 测试二级缓存是否开启

@Testpublic void test() throws Exception {Session session = HibernateUtils.getSession();Student student = session.get(Student.class, 0);System.out.println(student);session.close();Session session2 = HibernateUtils.getSession();Student student2 = session2.get(Student.class, 0);System.out.println(student2);}

测试结果

Hibernate: 
selectclasses0_.c_id as c_id1_1_0_,classes0_.c_name as c_name2_1_0_ 
fromclass classes0_ 
whereclasses0_.c_id=?Student{id=0, name='heqianqian', gender='female', birth=2017-04-30, address=Address{postCode='335400', phone='10086'}

注意:

  1. 二级缓存缓存的是对象 不会缓存属性
  2. 二级缓存不会缓存hql语句 需要配置:

hibernate.cfg.xml

  <!-- 开启查询缓存 --><property name="hibernate.cache.use_query_cache">true</property>

Student类上添加@Cachable注解

@Entity
@Table(name = "student", schema = "hibernate")
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)//表示开启二级缓存,并使用read-only策略
public class Student implements Serializable {

测试

@Testpublic void testHql() throws Exception {Session session = HibernateUtils.getSession();List<Student> list = session.createQuery("from Student ").setCacheable(true).list();Iterator<Student> students = (Iterator<Student>) list.iterator();while (students.hasNext()){System.out.println(students.next());}//session.close();Session session1 = HibernateUtils.getSession();List<Student> list1 = session.createQuery("from Student ").setCacheable(true).list();Iterator<Student> students1 = (Iterator<Student>) list1.iterator();while (students1.hasNext()){System.out.println(students1.next());}}

输出:

Hibernate: 
selectstudent0_.id as id1_0_,student0_.phone as phone2_0_,student0_.postcode as postcode3_0_,student0_.birth as birth4_0_,student0_.c_id as c_id7_0_,student0_.gender as gender5_0_,student0_.name as name6_0_ 
fromstudent student0_
Hibernate: selectclasses0_.c_id as c_id1_1_0_,classes0_.c_name as c_name2_1_0_ fromclass classes0_ whereclasses0_.c_id=?Student{id=0, name='heqianqian', gender='female', birth=2017-04-30, address=Address{postCode='335400', phone='10086'}Student{id=0, name='heqianqian', gender='female', birth=2017-04-30, address=Address{postCode='335400', phone='10086'}

参考文章:

http://www.cnblogs.com/xiaoluo501395377/p/3377604.html
http://blog.csdn.net/xlgen157387/article/details/40071651

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



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

相关文章

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

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

缓存雪崩问题

缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库无法使用。 解决方案: 1、使用锁进行控制 2、对同一类型信息的key设置不同的过期时间 3、缓存预热 1. 什么是缓存雪崩 缓存雪崩是指在短时间内,大量缓存数据同时失效,导致所有请求直接涌向数据库,瞬间增加数据库的负载压力,可能导致数据库性能下降甚至崩溃。这种情况往往发生在缓存中大量 k

java面试常见问题之Hibernate总结

1  Hibernate的检索方式 Ø  导航对象图检索(根据已经加载的对象,导航到其他对象。) Ø  OID检索(按照对象的OID来检索对象。) Ø  HQL检索(使用面向对象的HQL查询语言。) Ø  QBC检索(使用QBC(Qurey By Criteria)API来检索对象。 QBC/QBE离线/在线) Ø  本地SQL检索(使用本地数据库的SQL查询语句。) 包括Hibern

Redis中使用布隆过滤器解决缓存穿透问题

一、缓存穿透(失效)问题 缓存穿透是指查询一个一定不存在的数据,由于缓存中没有命中,会去数据库中查询,而数据库中也没有该数据,并且每次查询都不会命中缓存,从而每次请求都直接打到了数据库上,这会给数据库带来巨大压力。 二、布隆过滤器原理 布隆过滤器(Bloom Filter)是一种空间效率很高的随机数据结构,它利用多个不同的哈希函数将一个元素映射到一个位数组中的多个位置,并将这些位置的值置