【Hibernate 7】浅谈Hibernate的缓存机制

一、Hibernate缓存机制简介

对于Hibernate本身来说,它的缓存主要包括三部分:session缓存(一级缓存)、二级缓存、查询缓存。

1.1,session缓存

随着session的关闭而消失,load、iterator操作,会从一级缓存中查找数据,如果找不到,再到数据库里面查找。Query.list操作,如果没有配置查询缓存,将直接从数据库中获取数据。

特点:只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象形式.缓存的生命周期依赖于事务的生命周期,只有当事务结束时,缓存的生命周期才会结束。事务范围的缓存使用内存作为存储介质,一级缓存属于事务范围。

1.2,二级缓存

hibernate并没有提供相应的二级缓存的组件,所以需要加入额外的二级缓存包,常用的二级缓存包是EHcache。这个我们在下载好的hibernate的lib下可以找到,然后将里面的几个jar包导入即可。

为什么要有二级缓存:

一级缓存是session级别,也就是事务级别的。当session关闭后,一级缓存就不存在了,当再次需要获取数据的时候,需要再次发送sql语句。为了解决session关闭,缓存失效的问题,我们配置二级缓存。

特点:

可以被应用范围内的所有事务共享访问,缓存的生命周期依赖于应用的生命周期,只有当应用结束时,缓存的生命周期才会结束。应用范围的缓存可以使用内存或硬盘作为存储介质,二级缓存属于应用范围。

1.3,查询缓存

所谓查询缓存,即让hibernate缓存list、iterator、createQuery等方法的查询结果集。如果没有打开查询缓存,hibernate将只缓存load方法获得的单个持久化对象。在打开了查询缓存之后,需要注意,调用query.list()操作之前,必须显式调用query.setCachable(true)来标识某个查询使用缓存。

二、实例分析二级缓存

2.1,配置二级缓存

首先,由于Hibernate的二级缓存是通过使用第三方包encache实现的,所以我们需要配置一个encache.xml的文件,来配置我们的缓存信息,并将这个文件放在项目根目录下

<span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:18px;"><ehcache>

    <!-- Sets the path to the directory where cache .data files are created.

         If the path is a Java System Property it is replaced by
         its value in the running VM.

         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
  
  <!--指定二级缓存存放在磁盘上的位置-->
    <diskStore path="user.dir"/>  

  <!--我们可以给每个实体类指定一个对应的缓存,如果没有匹配到该类,则使用这个默认的缓存配置-->
    <defaultCache
        maxElementsInMemory="10000"  //在内存中存放的最大对象数
        eternal="false"         //是否永久保存缓存,设置成false
        timeToIdleSeconds="120"    
        timeToLiveSeconds="120"    
        overflowToDisk="true"     //如果对象数量超过内存中最大的数,是否将其保存到磁盘中,设置成true
        />
  
  <!--
    1、timeToLiveSeconds的定义是:以创建时间为基准开始计算的超时时长;
    2、timeToIdleSeconds的定义是:在创建时间和最近访问时间中取出离现在最近的时间作为基准计算的超时时长;
    3、如果仅设置了timeToLiveSeconds,则该对象的超时时间=创建时间+timeToLiveSeconds,假设为A;
    4、如果没设置timeToLiveSeconds,则该对象的超时时间=max(创建时间,最近访问时间)+timeToIdleSeconds,假设为B;
    5、如果两者都设置了,则取出A、B最少的值,即min(A,B),表示只要有一个超时成立即算超时。

  -->

  <!--可以给每个实体类指定一个配置文件,通过name属性指定,要使用类的全名-->
    <cache name="com.angel.hibernate.Student"
        maxElementsInMemory="100"
        eternal="false"
        timeToIdleSeconds="10000"
        timeToLiveSeconds="10000"
        overflowToDisk="true"
        />

    <cache name="sampleCache2"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        /> -->

</ehcache></span></span>

其次,配置Hibernate.cfg.xml文件,启用二级缓存

<span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:18px;"></pre><pre name="code" class="html">	<!-- 配置缓存提供商 -->
	<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
	<!--Hibernate4以上的提供商配置
	<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
	-->
	<!-- 启用二级缓存,这也是它的默认配置 -->
	<property name="hibernate.cache.use_second_level_cache">true</property>

	<!-- 二级缓存配置文件的位置 -->
        <property name="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</property>

	<!-- 指定Student使用二级缓存 -->
	<class-cache class="com.angel.hibernate.Student" usage="read-only"/></span></span>

2.2,配置实体映射文件的缓存

<span style="font-family:KaiTi_GB2312;font-size:18px;"><?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.bjpowernode.hibernate.Student" table="t_student">
		<!-- 二级缓存一般设置为只读的 -->
		<cache usage="read-only"/>
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name"/>
		<many-to-one name="classes" column="classesid"/>
	</class>
</hibernate-mapping></span></span>

2.3,实例测试二级缓存

<span style="font-family:KaiTi_GB2312;font-size:18px;"><span style="font-family:KaiTi_GB2312;font-size:18px;">/**
* 开启二级缓存
*
* 在两个session中发load查询
*/
public void testCache1() {
	Session session = null;
	try {
		session = HibernateUtils.getSession();
		session.beginTransaction();
		Student 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);
	}

	try {
		session = HibernateUtils.getSession();
		session.beginTransaction();
		Student student = (Student)session.load(Student.class, 1);

		//不会发出查询语句,因为配置二级缓存,session可以共享二级缓存中的数据
		System.out.println("student.name=" + student.getName());
		session.getTransaction().commit();
	}catch(Exception e) {
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally {
		HibernateUtils.closeSession(session);
	}</span></span>

三、实例分析查询缓存

首先,Hibernate.cfg.xml配置

<span style="font-family:KaiTi_GB2312;font-size:18px;"><!-- 启用查询缓存,默认是false是不起用的 -->
<property name="hibernate.cache.use_query_cache">true</property></span>

其次,在应用缓存是还需要开启查询缓存

<span style="font-family:KaiTi_GB2312;font-size:18px;">List names = session.createQuery("select s.name from Student s").setCacheable(true).list();</span>

注意:

1,查询缓存,和session的生命周期没有联系,它同样属于应用程序级别的缓存

2,使用query.iterate()查询普通的属性,将不会启动查询缓存,查询缓存只对query.list()起作用

3,如果关闭二级缓存,只启用查询缓存,那么查询缓存会缓存实体对象的id,当第二次执行query.list的时候,将缓存中的id取出,分别到一级和二级缓存中查询相对应的实体,如果存在,则直接使用对象,否则发出查询的sql语句。而如果我们关闭二级缓存,那么查询时将不能再缓存中找到实体对象,则会发出N条查询子句,将再次引起N+1问题,所以在应用查询缓存的时候,一定要开启二级缓存。

四、总结

以上就是Hibernate中关于缓存机制的总结,但在实际应用中,我们仍然需要对缓存进行管理,比如:

一级缓存的管理:

1,evit(Object obj)  将指定的持久化对象从一级缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象

2,clear()  将一级缓存中的所有持久化对象清除,释放其占用的内存资源

3,contains(Object obj) 判断指定的对象是否存在于一级缓存中

4,flush() 刷新一级缓存区的内容,使之与数据库数据保持同步

二级缓存的管理:

1,evict(Class arg0, Serializable arg1)  将某个类的指定ID的持久化对象从二级缓存中清除,释放对象所占用的资源

2,evict(Class arg0)  将指定类的所有持久化对象从二级缓存中清除,释放其占用的内存资源

3,evictCollection(String arg0)  将指定类的所有持久化对象的指定集合从二级缓存中清除,释放其占用的内存资源

时间: 2024-08-28 11:04:14

【Hibernate 7】浅谈Hibernate的缓存机制的相关文章

浅谈浏览器的缓存机制

浏览器的缓存可分为HTTP缓存和离线缓存,下面将分别介绍 HTTP缓存 只有GET请求能被缓存,POST不能被缓存.Modified Time/ETag/Expires/Cache都是HTTP协议的缓存策略 先来一个例子 当我们第二次访问百度首页,在Chrome的Network面板中打开一个静态文件时会发现响应的status是:200 OK (from disk cache),不是应该返回304 Not Modified吗?如果你知道答案,那就可以忽略本文了. Cache-Control 简介

浅谈Hibernate关系映射(3)

继上篇博客 一对多关联映射(单向) 上面我们介绍了多对一,我们反过来看一对多不就是多对一吗?那还用再进行不同的映射吗?有什么差别吗?一对多和多对一映射原理是一致的,存储是相同的,也就是生成的数据库的表是一样的,他们之间不同的是维护的关系不同. 他们之间不同点是维护的关系不同 *多对一维护的关系是:多指向一的关系,有了此关系,加载多的时候可以将一加载上来. *一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来. 一个班级有多个学生,通过班级可以看到学生信息. Class

浅谈Hibernate关系映射(2)

继上篇博客 一对一关系映射:一对一关联映射在实际生活中是比较常见的,如人与身份证的关系,通过人这个对象可以找到他相关的内容. 一对一单向(主键): 单向一对一主键关联,靠的是它们的主键相等,从Person中能看到IdCard,也就是把t_idCard中的主键拿过来当做t_Pseron的主键. 如图的线表示一个关联,在person中可以看见idcard.即在person中持有idCard的引用 person类的映射关系 <hibernate-mapping> <class name=&qu

浅谈Hibernate关系映射(4)

继上篇博客 多对多关联映射(单向) 多对多对象关系映射,需要加入一张新表完成基本映射. Hibernate会自动生成中间表 Hibernate使用many-to-many标签来表示多对多的关联,多对多的关联映射,在实体类中,跟一对多一样,也是用集合来表示的. 如下图所示 通过User可以查看Role的信息 User的映射文件 <hibernate-mapping> <class name="com.bjpowernode.hibernate.User"> <

浅谈mysql innodb缓存策略

浅谈mysql innodb缓存策略: The InnoDB Buffer Pool Innodb 持有一个存储区域叫做buffer pool是为了在内存中缓存数据和索引,知道innodb bufferpool怎么工作,和利用它读取频繁访问的数据,是mysql优化重要的方面. 理想状况下,把bufferpool的大小调整到足够大,留下足够的内存空间给其他该服务器上的进程(使其无缺页即可).bufferpool越大,innodb 月表现为内存型数据库,从硬盘上一次读取数据,之后并成了从内存中读取数

浅谈Android 事件分发机制(一)

在上一篇文章中,浅谈Android 事件分发机制(一),简要分析了一下事件分发机制的原理,总结一下就是事件层层传递,直到被消费,原理看似简单,但是在实际使用过程中,场景各不相同,复杂程度也就因产品而异,这篇文章就通过给view加移动来模拟事件分发. 触摸事件 这里涉及到几个与手指触摸相关的常见事件: 坐标系对于单指触控移动来说,一次简单的交互流程是这样的:手指落下(ACTION_DOWN) -> 移动(ACTION_MOVE) -> 离开(ACTION_UP) 坐标系 Android坐标系以手

浅谈Hibernate缓存机制:一级缓存、二级缓存

一:什么是缓存机制 当我们频繁访问数据库时,尤其像Hibernate持久层框架,会导致数据库访问性能降低,因此我们期望有一种机制能提供一个"缓存空间",我们将需要的数据复制到这个"缓存空间",当数据查询时,我们先在这个"缓存空间"里找,如果没有,我们再去数据库查找,这样就减少了与数据库的访问,从而提高了数据库访问性能,这就是缓存机制. 二:Hibernate缓存机制 1:一级缓存:Hibernate默认的缓存机制,它属于Session级别的缓存机

Hibernate中的HQL查询与缓存机制

HQL:完全面向对象查询 SQL的执行顺序: 1.From 2.Where 过滤基础数据 where与having的区别:1.顺序不同 2.where过滤基础数据 3. 过滤聚合函数 3.Group by 4.Select 5.Having 6.Order by   使用Hibernate查询时,使用hibernate的一个接口query Hql是面向对象的查询语句,所以跟的是类名 Query query = session.createQuery("select id,name,stu.cla

浅谈hibernate的sessionFactory和session

首先,讲一个悲伤的故事... 有一天,一个以为自己javaEE很叼的程序员,在经历了好久不写java代码的情况下,去参加阿里巴巴的java面试,然后,在被问到一个很简单的问题的时候,结果没有回答好.那么接下来先说说这个问题吧... 问:hibernate的sessionfactory是干嘛的?session又是干嘛的呢? 那么,你会吗?可以讲清楚么?如果答案是会,可以,那么你就不用往下看了....如果会还是想往下看,那么, 你就看呗. 在回答这个问题之前,先来看看一些概念. 一.hibernat