Hibernate之二级缓存运用

本文深入探讨缓存的概念及其在应用程序性能优化中的作用,着重解析二级缓存的机制与配置方法,包括缓存结构图、配置步骤、ehcache配置文件解析、配置效果验证以及二级缓存的存储区域与数据管理策略。

        缓存是介于应用程序与永久性存储介质之间的一块数据存储区域。它的数据都是从永久性存储介质得来的,缓存只是一个辅助性的区域,而不是数据最终存放的位置。利用它,应用程序可以将使用的数据临时放入缓存,当我们再次使用时就可以去缓存中获取,降低应用程序与永久性介质之间数据交换的频率,提升应用程序的运行性能,提升了查询效率。

        二级缓存是在已有的缓存基础上,在增设一种缓存,它只为一级缓存服务。二级缓存弥补了一级缓存的不足,一级缓存是针对单次操作而设计的,只服务一次请求操作,因此存储的数据量较小,生命周期较短,当一次操作完毕后,下一次请求的数据将无法使用上一次缓存的数据。二级缓存在一级缓存的基础上,在多次请求操作间进行数据共享,有效减少访问永久介质的次数,从而弥补了一级缓存的缺陷。目前hibernate支持的二级缓存有ehcache、OpenSymphony、SwarmCache和JBossCache。

        二级缓存的出现,有效的提高了信息查询的速度,但是并不是配置二级缓存后将所有数据放入二级缓存一定能加快速度,不合理的使用会降低整体应用的性能。在实际开发过程中,前期必须对数据进行合理的分析,有选择将数据放入二级缓存,而不是盲目的开启使用二级缓存。一般将很少被修改的数据、不是很重要的数据,允许出现偶尔并发的数据、不会被并发访问的数据和参考数据等加入二级缓存中,而那些经常被修改的数据、财务数据,绝对不允许出现并发和与其它应用共享的数据。

缓存的结构图

二级缓存的配置步骤

下面的配置以老师和学生来讲解(假定老师对学生是一对多的关系,操作ehcache)

一、操作前的准备阶段

老师数据表

老师实体类

public class TeacherModel {
	private Long uuid;
	private String teacherName;
	private String nick;

	private Set<StudentModel> students = new HashSet<StudentModel>();

学生数据表

学生实体类

public class StudentModel {
	private Long uuid;
	private String studentName;
	private Integer age;
	private String skill;

	private TeacherModel teacher;

二、配置二级缓存的步骤

1、导入jar包

2、在hibernate.cfg.xml中配置实用二级缓存、二级缓存供应商和开启二级缓存

<!-- 配置当前环境使用二级缓存 -->
<property name="cache.use_second_level_cache">true</property>
<!-- 配置二级缓存供应商 -->
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<!-- 配置开启查询缓存 -->
<property name="cache.use_query_cache">true</property>

3、添加二级缓存配置信息,控制哪些数据进入二级缓存

第一种配置方式(主流配置方式):在hibernate.cfg.xml配置

<!-- 使用class-cache定义类对象缓存,usage定义了缓存的种类:读写缓存、只读缓存等,class配置的是加入缓存的类模型
-->
<class-cache usage="read-write" class="cn.itcast.hibernate.o2m.vo.StudentModel" />
<class-cache usage="read-write" class="cn.itcast.hibernate.o2m.vo.TeacherModel" />
<!--使用collection-cache定义集合对象缓存,注意class中定义的是关联关系中的集合对象名
	 ,而不是关联模型类,更不是集合,usage定义了缓存的种类:读写缓存、只读缓存等。
		 -->
<collection-cache usage="read-write" collection="cn.itcast.hibernate.o2m.vo.TeacherModel.students"/>

第二种配置方式:在hbm.xml中配置

<hibernate-mapping>
	<class name="cn.itcast.hibernate.o2m.vo.TeacherModel" table="tbl_teacher">
		<cache usage="read-write" /><!-- 在class元素中,作为子元素出现 -->
		<id name="uuid" column="uuid">
			<!-- assigned、identity、native -->
			<generator class="native" />
		</id>
		<property name="teacherName" column="teacherName" />
		<property name="nick" column="nick" />

		<set name="students" inverse="true">
			<cache usage="read-write" />	<!-- 在set元素中,作为子元素出现 -->
			<key column="teacherUuid"></key><!-- 外键 -->
			<one-to-many class="cn.itcast.hibernate.o2m.vo.StudentModel" />
		</set>
	</class>
</hibernate-mapping>

4、配置ehcache自身设定值(在src目录下创建配置文件ehcache.xml)

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />
</ehcache>

      maxElementsInMemory="10000"                     //缓存最大元素数量(重点)

      eternal="false"                                                      //缓存数据是否过期

      timeToIdleSeconds="120"                                  //缓存数据最大不活动间隔(重点)

      timeToLiveSeconds="120"                                 //缓存数据最大生命周期(重点)

      overflowToDisk="true"                                      //缓存溢出数据是否持久化

      maxElementsOnDisk="10000000"                  //永久介质最大元素存储数量

      diskPersistent="false"                                       //JVM退出时是否进行永久介质存储

      diskExpiryThreadIntervalSeconds="120"      //缓存过期数据维护周期

      memoryStoreEvictionPolicy="LRU"               //缓存溢出数据处理策略(LRU最少使用,LFU时间段最不常使用,FIFO先进先出)

按以上内容配置好了,那么让我们看看是否配置成功,参考代码如下

@Test
	public void fun1(){
		Session s1=HibernateUtil.getSession();
		TeacherModel tm=(TeacherModel) s1.get(TeacherModel.class, 2L);
		System.out.println(tm);
		System.out.println(tm.getStudents());
		s1.close();
		
		System.out.println("-------------------------------------------------------------------");
		
		Session s2=HibernateUtil.getSession();
		TeacherModel tm2=(TeacherModel) s2.get(TeacherModel.class, 2L);
		System.out.println(tm2);
		System.out.println(tm2.getStudents());
		s2.close();
	}

结果为这样的就OK了:

读取二级缓存数据

        二级缓存的数据必须先加载才可以使用,如果二级缓存中没有要查找的数据,在进行了对应的查找操作后,该数据立即进入二级缓存。l二级缓存的数据获取必须按照OID进行,因此查询方法中不是按照OID进行的查询将不能从二级缓存获取。
1、一级缓存和二级缓存都不存在的过程图
2、一级缓存中存在要查的数据
3、二级缓存中存在要查的数据
4、使用SQL查询包括使用Query对象和Criteria对象查询
使用SQL查询的数据(不做缓存数据存在性检测)
执行SQL语句获取要查询的数据
将查询的数据更新到一级缓存中
一级缓存将变化的数据更新到二级缓存中
将查询的数据返回给客户端
5、添加操作数据不进入二级缓存
更新所在一级缓存的数据
更新数据库对应数据
6、删除和修改操作影响二级缓存
更新所在一级缓存的数据
一级缓存将变化的数据更新到二级缓存
更新数据库对应数据
 
二级缓存的4个存储区域
1、类对象缓存区
散装数据:将一个数据拆分开,然后分别存储独立的数据
注意:一级缓存从二级缓存中获取的数据不是对象,而是将一些散装数据重新组装成对象后加入一级缓存
2、关联关系集合对象缓存区
l二级缓存中的集合数据仅保存对应对象在类对象缓存区保存数据的OID,集合中不存在任何OID之外的属性数据,因此集合数据如果没有设定对应的类对象缓冲区将失去缓存的意义
3、为某些需要进行更新的数据进行标志添加,下一次访问该数据时,如果携带有更新标志,必须从数据库从新读取,覆盖二级缓存的数据。 无论修改操作是否影响到当前数据,只要进行了对某个表的操作,二级缓存中对应的全部数据必须reload
4、查询缓存的数据只能从查询缓存中获取,与二级缓存中其他区域的数据没有关系,因此每次都要设定使用查询缓存
<property name="cache.use_query_cache">true</property>
对要进行查询缓存的操作开始使用查询缓存设置
Query q = session.createQuery(hql);
		q.setCacheable(true);
		List<Object[]> queryList = q.list();
二级缓存数据存储区
 
 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值