【Hibernate】一级、二级缓存

本文讲述HIbernate中一级、二级缓存的概念以及如何使用。

一、大纲

2.什么是一级缓存

3.一级缓存示例展示

4.二级缓存以及示例展示

5.总结

二、什么是一级缓存

在hibernate中所谓的一级缓存就是session对象,但是一级缓存对提高性能的作用性并不是很大,其session主要的目的是管理实体对象的状态(临时、离线、持久化)。

其缓存模型如下图:

三、一级缓存示例

3.1 查询(get,load, HQL)

3.1.1 get/load方法

@Test
	public void testGet() {
		Session session = factory.openSession();
		Transaction tx = session.beginTransaction();
		tx.begin();
		// 第一次查询
		User user1 = (User)session.get(User.class, 1);
		System.out.println(user1);
		// 如果session中存在id=1的User对象缓存,那么再次查询时,将不需要执行SQL
		User user2 = (User)session.get(User.class, 1);
		System.out.println(user2);
		tx.commit();
		session.close();
	}

如果执行第二次查询在session关闭之后,那么会抛出异常,session已经关闭。load方法类型,只是其支持懒加载查询。

3.1.2 Hql查询

@Test
	public void testHqlQueryFromCache() throws Exception {
		Session session = factory.openSession();
		Transaction tx = session.beginTransaction();
		tx.begin();
		// 使用HQL查询id=1的User对象,此时会将id=1的对象写入到session缓存中
		User user1 = (User)session.createQuery("FROM User WHERE id = 1").uniqueResult();
		System.out.println(user1);
		System.out.println("================");
		// 执行第二次同样查询,默认情况无法从session中获取id=1的对象,但是也会将id=1的对象写入session缓存中
		User user2 = (User)session.createQuery("FROM User WHERE id = 1").uniqueResult();
		System.out.println(user2);
		System.out.println("================");
		// 使用get方法查询,由于session中已经存在id=1的对象,所以不会执行SQL
		User user3 = (User)session.get(User.class, 1);
		System.out.println(user3);
		tx.commit();
		session.close();
	}

3.2 Update/delete对Session的影响

在session执行查询之后,如果此时执行update或者delete操作,session中的数据是否会发生变化呢?通过下面这个例子展示:

@Test
	public void testUpdate() {
		Session session = factory.openSession();
		Transaction tx = session.beginTransaction();
		tx.begin();
		// 执行查询操作,将id=1的数据,存放在session中
		User user = (User)session.get(User.class, 1);
		System.out.println(user);
		// 执行update操作,将id=1的数据修改
		session.createQuery("UPDATE User SET name = ? WHERE id = 1").setParameter(0, "updateOrDelete").executeUpdate();
		// 如果执行的update操作,修改了session中的实体name属性,那么获取时将得到updateOrDelete值,否则保持变
		User user2 = (User)session.get(User.class, 1);
		System.out.println(user2);
		tx.commit();
		session.close();
	}

    得出结论update或者delete(这里未展示delete操作),不会修改当前session的数据,只能等待下次session查询,或者手动使用session.refresh()/clear等刷新session数据。

四、二级缓存以及示例展示

4.1 什么是二级缓存

二级缓存实际上是提供了一个公共数据缓存库,用于提高查询性能,当对数据的实时性要求非常高时,没有必要使用二级缓存,二级缓存模型如下:

    可以理解为二级缓存是不同session的共享数据,而一级缓存是针对同一个session操作的。

4.2 配置二级缓存

Hibernate默认并不使用二级缓存,如果使用的话,需要配置一些参数提供使用;

1、配置二级缓存类型(提供者)《hibernate.cfg.xml配置中》

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

2、设置需要配置的实体类、集合、查询条件

<!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>
<!-- 实体类 -->
<class-cache usage="read-write" class="com.hibernate.seconde_cache.User" />
<!-- 注:也可以在实体映射文件中配置<cache>这里不做介绍 -->

4.3 各种类型缓存处理

在4.2中粗略的展示了一些基本的二级缓存配置,在此节中将主要展示三种情况二级缓存配置。

4.3.1 单个实体二级缓存

1)配置

<!-- 设置缓存提供者 -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
<!-- 实体类 -->
<class-cache usage="read-write" class="com.hibernate.seconde_cache.User" />

2)示例展示

@Test
	public void testSingleEntity() throws Exception {
		// 第一个session,存储数据
		Session session1 = factory.openSession();
		Transaction tx1 = session1.beginTransaction();
		tx1.begin();
		User user1 = (User)session1.get(User.class, 1);
		System.out.println(user1);
		tx1.commit();
		session1.close();

		System.out.println("\n===================\n");

		// 第二个session读取第一个session的数据
		Session session2 = factory.openSession();
		Transaction tx2 = session2.beginTransaction();
		tx2.begin();
		User user2 = (User)session2.get(User.class, 1);
		System.out.println(user2);
		tx2.commit();
		session2.close();
	}

3)update和delete对二级缓存的影响

	@Test
	public void testSingleEntityOfUpdate() throws Exception {
		// 第一个session,存储数据
		Session session1 = factory.openSession();
		Transaction tx1 = session1.beginTransaction();
		tx1.begin();
		User user1 = (User)session1.get(User.class, 1);
		System.out.println(user1);
		tx1.commit();
		session1.close();

		System.out.println("\n===================\n");

		Session updateSession = factory.openSession();
		updateSession.createQuery("UPDATE User SET name=? WHERE id = 1").setParameter(0, "Second Cache").executeUpdate();

		System.out.println("\n===================\n");

		// 第二个session读取第一个session的数据
		Session session2 = factory.openSession();
		Transaction tx2 = session2.beginTransaction();
		tx2.begin();
		User user2 = (User)session2.get(User.class, 1);
		System.out.println(user2);
		tx2.commit();
		session2.close();
	}

由此可以update和delete的操作,会即使影响二级缓存的操作,其他session可以及时发现

4.3.2 查询条件缓存

在介绍如何缓存查询条件之前,如何通过Hibernate提供的方法实现缓存,并解释此种方法的不良效果,以及引入查询条件如何缓存。

1)非查询条件实现缓存(缓存配置同4.3.1)

使用list执行相同查询条件,依旧重复执行SQL

@Test
	public void testHql() throws Exception {
		// 第一个session,存储数据
		Session session1 = factory.openSession();
		Transaction tx1 = session1.beginTransaction();
		tx1.begin();
		List user1= session1.createQuery("FROM User").list();
		System.out.println(user1);
		tx1.commit();
		session1.close();

		System.out.println("\n===================\n");

		// 第二个session读取第一个session的数据
		Session session2 = factory.openSession();
		Transaction tx2 = session2.beginTransaction();
		tx2.begin();
		List user2 = session2.createQuery("FROM User").list();
		System.out.println(user2);
		tx2.commit();
		session2.close();
	}

使用iterate方法替代list方法,但是会出现N+1此查询问题,先查询符合条件的Id,之后在根据Id查询。

@Test
	public void testHqlOfIterate() throws Exception {
		Session session1 = factory.openSession();
		Transaction tx1 = session1.beginTransaction();
		tx1.begin();
		// 使用iterate方法替代List方法
		Iterator<User> users1= session1.createQuery("FROM User").iterate();
		while(users1.hasNext()) {
			System.out.println(users1.next());
		}
		tx1.commit();
		session1.close();

		System.out.println("\n===================\n");

		Session session2 = factory.openSession();
		Transaction tx2 = session2.beginTransaction();
		tx2.begin();
		Iterator<User> users2= session2.createQuery("FROM User").iterate();
		while(users2.hasNext()) {
			System.out.println(users2.next());
		}
		tx2.commit();
		session2.close();
	}

2)使用查询条件缓存

配置相比于4.3.1需要添加:

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

就如1)中所属,使用查询条件过滤,可以减少1)中的查询次数,大大提高查询效率:

@Test
	public void testHqlOfCondition() throws Exception {
		Session session1 = factory.openSession();
		Transaction tx1 = session1.beginTransaction();
		tx1.begin();
		// 通过执行setCacheable(true)方法,表示将此次查询条件缓存
		// 也就是以FROM Use WHERE id < 4为键存储,值:对应查询的结果集
		List list1= session1.createQuery("FROM User WHERE id < 4").setCacheable(true).list();
		System.out.println(list1);
		tx1.commit();
		session1.close();

		System.out.println("\n===================\n");

		Session session2 = factory.openSession();
		Transaction tx2 = session2.beginTransaction();
		tx2.begin();
		List list2= session2.createQuery("FROM User WHERE id < 4").setCacheable(true).list();
		System.out.println(list2);
		tx2.commit();
		session2.close();
	}

注:查询条件必须保持一直,否则视为不同查询条件。delete和update操作与4.3.1的影响一致,这里不做效果展示。

4.3.3 集合元素查询缓存展示

示例实体映射模型为(班级、学生方式《多对1的关系》),具体的映射代码、实体类代码这里不展示。

1)配置(相比4.3.1添加如下配置)

<!-- 配置班级实体缓存 -->
<class-cache usage="read-write" class="com.hibernate.seconde_cache.Classes"/>
<!-- 配置学生实体缓存 -->
<class-cache usage="read-write" class="com.hibernate.seconde_cache.Student"/>
<!-- 配置班级中的学生集合缓存,注意使用的方式是类全限定名.属性名 -->
<collection-cache usage="read-write" collection="com.hibernate.seconde_cache.Classes.students"/>

2)代码示例:

	@Test
	public void testSet() throws Exception {
		Session session1 = factory.openSession();
		Transaction tx1 = session1.beginTransaction();
		tx1.begin();
		// 查询id=1的班级
		Classes classes1 = (Classes)session1.get(Classes.class, 1);
		System.out.println(classes1);
		// 执行懒加载获取数据;如果想将集合元素也缓存,那么必须添加集合配置
		System.out.println(classes1.getStudents());

		tx1.commit();
		session1.close();

		System.out.println("\n===================\n");

		Session session2 = factory.openSession();
		Transaction tx2 = session2.beginTransaction();
		tx2.begin();
		// 第二个session,获取二级缓存中的数据
		Classes classes2 = (Classes)session2.get(Classes.class, 1);
		System.out.println(classes2);
		System.out.println(classes2.getStudents());
		tx2.commit();
		session2.close();
	}

如果没有添加

<collection-cache usage="read-write" collection="com.hibernate.seconde_cache.Classes.students"/>

那么会出现如下结果:

五、总结

涉及到的二级缓存知识,远远比本文多,一般不会使用本文中的Hashtable提供者,通常使用:

1级缓存是必须使用的,因为任何操作都需要使用到session,但是其对性能提高影响不大,而二级缓存对那些对数据实时性以及准确性要求不高的情况,建议使用,可以提高查询性能。

时间: 2024-08-07 00:17:04

【Hibernate】一级、二级缓存的相关文章

Hibernate的一级二级缓存机制配置与测试

特别感谢http://www.cnblogs.com/xiaoluo501395377/p/3377604.html 在本篇随笔里将会分析一下hibernate的缓存机制,包括一级缓存(session级别).二级缓存(sessionFactory级别)以及查询缓存,当然还要讨论下我们的N+1的问题. 随笔虽长,但我相信看完的朋友绝对能对hibernate的 N+1问题以及缓存有更深的了解. 一.N+1问题 首先我们来探讨一下N+1的问题,我们先通过一个例子来看一下,什么是N+1问题: list(

Hibernate的二级缓存

与Session的一级缓存相对的是,SessionFactory也提供了相应的缓存机制(二级缓存).SessionFactory缓存可以依据功能和目的的不同而划分为内置缓存和外置缓存. SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的副本,而预定义SQL语句是在 Hibernate初始化阶段根据映射元数据推导出来的.SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义 SQL语句,因此SessionFa

Hibernate之二级缓存

Hibernate缓存 缓存(Cache):计算机领域非常通用的概念.它介于应用程序和永久性数据存储源(如硬盘上的文件或数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能.缓存中的数据时数据存储源中数据的拷贝.缓存的物理介质通常是内存 Hibernate中提供了两个级别的缓存 第一级别的缓存是Session级别的缓存,它是属于事务范围的缓存.这一级别的缓存有Hibernate管理的 第二级别的缓存是SessionFactory级别的缓存,它是属于进程范围的缓

【SSH网上商城项目实战16】Hibernate的二级缓存处理首页的热门显示

网上商城首页都有热门商品,那么这些商品的点击率是很高的,当用户点击某个热门商品后需要进入商品的详细信息页面,就像淘宝里面那样.那么每次点击都要去后台查询一下该商品的详细信息,就会发送相应的sql语句,每次刷新一下详细页面也会发sql语句,这样的话,性能肯定会受到很大的影响.那么使用Hibernate的二级缓存就可以解决这个问题. 有些人可能会想,我们可以使用重定向,这样的话,在用户第一次访问的时候把信息查出来放到session中,以后每次用户刷新就可以去session中拿了,这样就不用去数据库中

Hibernate的二级缓存策略

Hibernate的二级缓存策略的一般过程如下: 1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象. 2) 把获得的所有数据对象根据ID放入到第二级缓存中. 3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查:查不到,如果配置了二级缓存,那么从二级缓存中查:查不到,再查询数据库,把结果按照ID放入到缓存. 4) 删除.更新.增加数据的时候,同

hibernate(九) 二级缓存和事务级别详讲

序言 这算是hibernate的最后一篇文章了,下一系列会讲解Struts2的东西,然后说完Struts2,在到Spring,然后在写一个SSH如何整合的案例.之后就会在去讲SSM,在之后我自己的个人博客应该也差不多可以做出来了.基本上先这样定下来,开始完成hibernate的东西把.这章结束后,我会将我一些hibernate的资料奉上,供大家一起学习. ---WH 一.概述 这章总的分两大块来讲解, 第一大块,hibernate的事务管理.,对于hibernate的事务管理来说,如果之前学过数

hibernate的二级缓存----collection和query的二级缓存

collection二级缓存: 不使用集合的二级缓存时: 运行下面的代码: @Test public void testCollectionSecondLevelCache1(){ Department dept = (Department) session.get(Department.class, 3); System.out.println(dept.getId()+" "+dept.getName()); System.out.println(dept.getEmps().si

Hibernate的二级缓存使用(spring使用)

(一)Hibernate的二级缓存策略的一般过程如下: 1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象. 2) 把获得的所有数据对象根据ID放入到第二级缓存中. 3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查:查不到,如果配置了二级缓存,那么从二级缓存中查:查不到,再查询数据库,把结果按照ID放入到缓存. 4) 删除.更新.增加数据的时

配置Hibernate的二级缓存

1.在applicationContex.xml文件里面添加二级缓存配置: <!-- 配置hibernate的sessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource"><ref bea

SSH整合缓存之-Memcached作为hibernate的二级缓存

Hibernate本身不提供二级缓存,所以需要使用第三方插件来作为二级缓存:本次使用memcached作为Hiberbate的二级缓存:添加步骤如下: 一.需要安装memcached服务端 1. 下载memcached的windows稳定版, (本次测试使用下载memcached http://www.newasp.net/soft/63735.html)2. 在CMD下进入memcached解压路径:输入 memcached.exe -d install" 安装. 3. 再输入:memcach