Hibernate学习笔记(六) — Hibernate的二级缓存

我们知道hibernate的一级缓存是将数据缓存到了session中从而减少与数据库的交互。那么二级缓存呢?

一、应用场合

比如,在12306购票时,需要选择出发地与目的地,如果每点一次都与数据库交互一次,这就很不合适,这些地点数据在相当长的一段时间内是不会发生变化的(山东省在相当长的时间内还叫山东省),所以应该缓存起来,没必要每次都与数据库交互,而且该类数据安全性也不是很高。

适合二级缓存的数据:

在现代软件开发中,确实存在一类数据没有什么私有性,为公开的数据,数据基本上不发生变化,该数据保密性不是很强,但又会经常被用到(比如火车票上的出发地与目的地数据)。

注意:如果一个数据一直在改变,不适合用缓存。

流式数据:数据时时刻刻在变的数据,比如手机应用获取手机所在地,后台的推送系统,发出一些信息,比如短信会提示你某天夜间流量超过多少,建议购买夜间流量。而这类数据适合使用strom来处理 。

二、生命周期

二级缓存为sessionFactory级别的缓存,其生命周期和sessionFactory是一致的,Hibernate启动后就有了.

二级缓存在Hibernate中的位置

所以Hibernate内部并没有实现二级缓存,而是应用第三方插件来实现二级缓存的。

三、二级缓存的设置

利用的是ehcache实现的二级缓存

1.添加ehcache所需的jar包

2.在hibernate的配置文件中进行配置

四、二级缓存的操作

哪些方法可以把对象放入到二级缓存中?

get方法,list方法可以把一个或者一些对象放入到二级缓存中

哪些方法可以把对象从二级缓存中提取出来?

get方法,iterator方法可以提取

注意:用的时候一定要小心使用各方法,取数据时,如果把list用成iterate会造成效率的及其降低

五、二级缓存的存储策略

read-only:对象只要加载到二级缓存以后,就只能读取,不能修改。

read-write:对二级缓存中的对象能够进行读和写的操作

注意:一般都设置为read-only

缓存得到磁盘

如果一个系统的权限特别大,这就不适合长时间的放入到二级缓存中,会导致占用内存逐渐变大,查询效率逐渐降低,这种情况可以二级缓存移到磁盘上,但是在现代开发如果需要缓存较多,一般都是使用分布式缓存。

测试:

hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

<session-factory>

	<property name="hibernate.dialect"><![CDATA[org.hibernate.dialect.MySQLDialect]]></property>
	<property name="hibernate.connection.driver_class"><![CDATA[com.mysql.jdbc.Driver]]></property>
	<property name="hibernate.connection.url"><![CDATA[jdbc:mysql:///hibernate1]]></property>
	<property name="hibernate.connection.username"><![CDATA[root]]></property>
	<property name="hibernate.connection.password"><![CDATA[qiaolezi]]></property>

	<property name="hibernate.c3p0.max_size">20</property>
	<property name="hibernate.c3p0.min_size">10</property>
	<property name="hibernate.c3p0.max_statements">10</property>
	<property name="hibernate.c3p0.acquire_increment">5</property>
	<property name="hibernate.c3p0.timeout">3000</property>

	<!-- 二级缓存供应商 -->
	<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
	<!-- 开启二级缓存 -->
	<property name="cache.use_second_level_cache">true</property>
	<!-- 开启二级缓存的统计机制 -->
	<property name="generate_statistics">true</property>

	<property name="hbm2ddl.auto">update</property>
	<property name="show_sql">true</property>
	<property name="current_session_context_class">thread</property>
	<property name="format_sql">true</property>

	<mapping resource="cn/cil/domain/Classes.hbm.xml" />
	<mapping resource="cn/cil/domain/Student.hbm.xml" />

</session-factory>
</hibernate-configuration>

Classes

public class Classes implements Serializable{

	private Long cid;
	private String name;
	private Set<Student> students;
}

Classes.hbm.xml

<class name="Classes" table="CLASSES">
		<cache usage="read-write"/><!-- 只读 -->
		<id name="cid">
			<generator class="native"></generator>
		</id>
		<property name="name"></property>
		<set name="students" cascade="save-update" inverse="true">
			<cache usage="read-only"/><!-- 设置集合的二级缓存 -->
		<!-- key:外键,告诉hibernate通过cid来建立classes与student的关系 -->
			<key column="cid"></key>
			<one-to-many class="Student"/>
		</set>
	</class>

Student

public class Student implements Serializable{

	private Long sid;
	private String name;
	private Classes classes;
}

Student.hbm.xml

<class name="Student" table="STUDENT">
		<id name="sid">
			<generator class="native"></generator>
		</id>
		<property name="name"></property>

		<many-to-one cascade="save-update" name="classes" column="cid" class="Classes">
		</many-to-one>
	</class>

测试类

public class SessionFactoryCacheTest {

	private Session session;
	private Transaction transaction;
	private SessionFactory sessionFactory;

	/**
	 * 测试get,在session关闭后,再次请求,不发出sql
	 * 该方法在取数据时,先从一级缓存中找,如果二级缓存开启了,接下来就会从二级缓存中,都没有,则查数据库
	 * 在DefaultLoadEventListener.class中可以清晰的看到
	 * 440行: 从一级缓存,459 行: 从二级缓存,477行: 从数据库
	 *
	 * get可以把对象放入二级缓存,也可以从二级缓存中取数据
	 */
	@Test
	public void testGet(){

		sessionFactory = HibernateUtils.getSessionFactory();
		 session = HibernateUtils.openSession();
		Classes classes = (Classes) session.get(Classes.class, 1L);
		System.out.println(sessionFactory.getStatistics()
				.getEntityLoadCount());//1
		session.close();
		session = HibernateUtils.openSession();
	    classes = (Classes) session.get(Classes.class, 1L);//不发出sql
		session.close();
	}
	/**
	 * Hibernate提供了二级缓存的统计机制
	 * save不能把对象存入二级缓存
	 */
	@Test
	public void testSave(){
		sessionFactory = HibernateUtils.getSessionFactory();
		session = HibernateUtils.openSession();
		transaction = session.beginTransaction();
		Classes classes = new Classes();
		classes.setName("a");
		session.save(classes);
		System.out.println(sessionFactory.getStatistics()
				.getEntityLoadCount());//0
		transaction.commit();
		session.close();
	}

	/**
	 * session.update不操作二级缓存
	 */
	@Test
	public void testUpdate(){
		sessionFactory = HibernateUtils.getSessionFactory();
		session = sessionFactory.openSession();
		Transaction transaction = session.beginTransaction();
		Classes classes = new Classes();
		classes.setCid(3L);
		classes.setName("afds");
		session.update(classes);
		System.out.println(sessionFactory.getStatistics()
				.getEntityInsertCount());//0
		transaction.commit();//会报错,但是不影响,设置为<cache usage="read-write">,如果集合也设置了二级缓存,那集合也要设置为同样
		session.close();
	}

	/**
	 * HQL中的list,可以把对象放入到二级缓存,但是不能从二级缓存取数据
	 */
	@Test
	public void testQueryList(){
		sessionFactory = HibernateUtils.getSessionFactory();
		session = sessionFactory.openSession();

		session.createQuery("from Classes").list();
		System.out.println(sessionFactory.getStatistics()
				.getEntityLoadCount());//不是0
		session.close();
		session = sessionFactory.openSession();
		session.createQuery("from Classes").list();//发出sql,因为getEntityLoadCount不为0,所以list()可以把对象放入二级缓存,但是不能从二级缓存中取对象
		session.close();
	}

	/**
	 *  iterator,可以从二级缓存中取数据
	 *  iterate方法的查询策略:
	 *  	先查找该表中所有的id值
	 *  	再根据id值从二级缓存中查找对象,如果有,则利用二级缓存,
	 *  						     如果没有,则根据id查询所有属性的值
	 */

	@Test
	public void testQueryIterate(){
		sessionFactory = HibernateUtils.getSessionFactory();
		session = sessionFactory.openSession();
		session.createQuery("from Classes").list();

		System.out.println(sessionFactory.getStatistics()
				.getEntityLoadCount());//不是0
		session.close();
		session = sessionFactory.openSession();
		Iterator<Classes> iterator = session.createQuery("from Classes").iterate();
		while (iterator.hasNext()) {
			Classes classes = (Classes) iterator.next();
			System.out.println(classes.getName());
		}

		session.close();
	}

	/**
	 * 集合的二级缓存,需要在hbm.xml文件中进行相应的设置
	 * 集合有一级缓存也有二级缓存
	 */
	@Test
	public void testCollection(){
		sessionFactory = HibernateUtils.getSessionFactory();
		session = sessionFactory.openSession();

		Classes classes = (Classes) session.get(Classes.class, 1L);
		Set<Student> students = classes.getStudents();
		for(Student student : students){
			System.out.println(student.getName());
		}
		System.out.println(sessionFactory.getStatistics()
				.getCollectionLoadCount());//1
		session.close();
	}

	/**
	 * 二级缓存 到 磁盘
	 */
	@Test
	public void testCacheDisk(){
		sessionFactory = HibernateUtils.getSessionFactory();
		session = sessionFactory.openSession();

		session.createQuery("from Classes").list();
		try {
			Thread.sleep(2000L);//停一会,否则写不进去数据
		} catch (Exception e) {

			e.printStackTrace();
		}
		session.close();
	}
}

二级缓存企业应用的不多,实在有些鸡肋

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 08-12

Hibernate学习笔记(六) — Hibernate的二级缓存的相关文章

Hibernate学习笔记(2)Hibernate问题

(1)数据库驱动问题 log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment). log4j:WARN Please initialize the log4j system properly. Exception in thread "main" org.hibernate.HibernateException: JDBC Driver class not found: com.m

Hibernate学习笔记(三) — Hibernate 的一级缓存意义

什么是缓存? 缓存说白了,就是应用程序向数据库要数据,然后把一些数据,临时的放在了内存的区域中,第二次再要数据的时候,直接从内存中拿即可. 缓存需要解决的事情: 1.能把数据放入缓存 2.能把数据从缓存中取出来 3.如果缓存中的数据发生变化,需要把数据同步到数据库中 4.把数据库中的数据同步到缓存中 5.hits命中率低的对象应该及时从缓存中移走 分布式缓存: 为什么会有分布式缓存? 应用程序运行在服务器上,并发访问时,服务器压力过大,分布式缓存就是来分担服务器压力的. 分布式缓存之间的数据是同

Hibernate学习笔记(一) — hibernate的配置文件简介与执行原理

一.初识Hibernate 1.JDBC的缺点: 1).编写代码的时候过于繁琐,try和catch比较多2).没有做数据缓存 3).不是面向对象编程 4).sql语句固定,可移植性差 JDBC的优点:效率比较高 2.Hibernate优点 1).完全面向对象编程 2).hibernate的缓存很牛的,一级缓存,二级缓存,查询缓存3).跨平台性强 4).使用场合多应用于企业内部的系统 Hibernate缺点 1).效率低 2).表中的数据如果在千万级别,则hibernate不适合 3).如果表与表

hibernate学习笔记之一 hibernate简介

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架 hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库. Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久

Hibernate学习笔记(九) — Hibernate的查询

Hibernate共提供以下三种检索方式 HQL检索方式: 1.通过 Session 的 createQuery() 方法创建一个 Query 对象, 它包括一个 HQL 查询语句. HQL 查询语句中可以包含命名参数 2.动态绑定参数 3.调用 Query 的 list() 方法执行查询语句. 该方法返回java.util.List 类型的集合, 在 List 集合中存放了符合查询条件的持久化对象. 4.Qurey 接口支持方法链编程风格, 它的 setXxx() 方法返回自身实例 Hiber

Hibernate学习笔记(3)

两年前曾经学习过Hibernate,也通过博客将Hibernate的学习过程记录下来了,地址如下: Hibernate学习笔记(1) Hibernate学习笔记(2) 最近在复习Hibernate,在重新学习的过程中,有了一些新的体会和收获,现在将其总结成博客,供以后作为参考资料使用. 一.导入相应的jar包 目前Hibernate更新到了4.x版本,在官网下载后,找到lib文件加中的required文件夹,此外还需要额外导入log4j和数据库驱动包. 二.创建Hibernate配置文件 在sr

hibernate学习笔记之三(一级缓存的使用和管理)

(hibernate学习笔记系列来自于 "疯狂Java" Hibernate视频学习) 一级缓存 一级缓存生命周期很短,与session生命周期一致,所以一级缓存也叫session级缓存或事务级缓存.位于缓存中的对象处于持久化状态,它与表中的相关记录对应,session能够在某些时间点,按照缓存中持久化对象的属性来同步数据库中表的记录,这一过程称为清理缓存. 一级缓存实现原理. session缓存是由它的实现类sessionImpl中定义的一些集合属性构成的,原理是保证有一个引用在关联

Hibernate学习笔记_02

上篇文章(传送门:Hibernate学习笔记_01)介绍了Hibernate是什么,如何搭建,配置文件详解以及Hibernate的一些基本API详解这几个方面做了简单介绍,那么本文将会从一下5个方面记录Hibernate的学习经历:1.hibernate中的实体规则 2.hibernate中的对象状态 3.hibernate进阶-- 一级缓存 4.hibernate中的事务 5.hibernate中的批量查询(概述) Ⅰ.Hibernate中的实体规则 在Hibernate使用中,需要创建与数据

《Hibernate学习笔记十一》:树状结构设计

<Hibernate学习笔记十一>:树状结构设计 这是马士兵老师讲解Hibernate的一个作业题,树状结构设计,这是一个比较典型的例子,因此有必要写篇博文记录下. 树状结构的设计,它是在同一个类中使用了多对一(ManyToOne)和一对多(OneToMany). 在完成这个题目我们应该按照如下的步骤进行: 1.先思考数据库的模型应该是什么样的?? 数据库中的模型应该如下:即存在id p_id 2.思考面向对象的模型,及如何来进行映射??? 根据数据库中表的特点,对象应该有id name;由于