hibernate之二级缓存

在hibernate中session缓存作为一级缓存,是事务缓存;SessionFactory缓存是二级缓存,是hibernate管理的进程缓存


要使用二级缓存,首先要在hibernate.cfg.xml中进行二级缓存的配置信息

<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
	
<hibernate-configuration>
<session-factory>
	<property name="dialect">
		org.hibernate.dialect.MySQLDialect
	</property>

	<property name="hibernate.connection.driver_class">
		com.mysql.jdbc.Driver
	</property>
	<property name="hibernate.connection.url">
		jdbc:mysql://localhost:3306/hibernate_example_01
	</property>
	<property name="hibernate.connection.username">root</property>
	<property name="hibernate.connection.password">123</property>


	<property name="show_sql">true</property>
	<property name="format_sql">false</property>
	
	<property name="hbm2ddl.auto">update</property>
	 <!-- <mapping resource="hibernate_a_helloword/User.hbm.xml" /> -->
 	


	
		<!-- 
			设置默认的事务隔离级别:
			隔离级别		对应的整数表示
			READ UNCOMMITED	1
			READ COMMITED	2
			REPEATABLE READ	4
			SERIALIZEABLE	8
		 -->
		<property name="connection.isolation">2</property>
		
		<!-- C3P0连接池设定-->
		<!-- 使用c3p0连接池  配置连接池提供的供应商-->
		<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider                                                                                                                                                     </property>
		<!--在连接池中可用的数据库连接的最少数目 -->
		<property name="c3p0.min_size">5</property>
		<!--在连接池中所有数据库连接的最大数目  -->
		<property name="c3p0.max_size">20</property>
		<!--设定数据库连接的过期时间,以秒为单位,
		如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
		<property name="c3p0.timeout">120</property>
		 <!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->
		<property name="c3p0.idle_test_period">3000</property>
		
	
		
		<!-- 使用二级缓存,默认是未打开的。 -->
		<!-- 指定要使用的缓存的提供商,这也就打开了二级缓存 
		<property name="cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
		-->
		<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
		<!-- 开启使用查询缓存 -->
		<property name="cache.use_query_cache">true</property>
		<!-- 指定要使用二级缓存的实体类 -->
		<class-cache usage="read-write" class="hibernate_a_example.Employee"/>
		<class-cache usage="read-write" class="hibernate_a_example.Department"/>
		<collection-cache usage="read-write" collection="hibernate_a_example.Department.employees"/>
	


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

然后就可以在类实现二级缓存

package hibernate_a_example;

import java.util.Iterator;
import java.util.List;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class App {

	private static SessionFactory sessionFactory = new Configuration()//
			.configure()//
			.addClass(Department.class)// 添加Hibernate实体类(加载对应的映射文件)
			.addClass(Employee.class)// 添加Hibernate实体类(加载对应的映射文件)
			.buildSessionFactory();

	// 测试一级缓存(Session缓存)
	@Test
	public void testSessionCache() throws Exception {
		// ===================== 第1个Session
		Session session = sessionFactory.openSession();
		session.beginTransaction();

		Employee employee = (Employee) session.get(Employee.class, 1); // 获取

		session.getTransaction().commit();
		session.close();

		// ===================== 第2个Session
		Session session2 = sessionFactory.openSession();
		session2.beginTransaction();

		Employee employee2 = (Employee) session2.get(Employee.class, 1); // 获取

		session2.getTransaction().commit();
		session2.close();
	}

	// 测试二级缓存
	@Test
	public void testSecondCache() throws Exception {
		// ===================== 第1个Session
		Session session = sessionFactory.openSession();
		session.beginTransaction();

		Department department = (Department) session.get(Department.class, 1); // 获取
		System.out.println(department.getName());
		System.out.println(department.getEmployees());

		session.getTransaction().commit();
		session.close();

		// ===================== 第2个Session
		Session session2 = sessionFactory.openSession();
		session2.beginTransaction();

		Department department2 = (Department) session2.get(Department.class, 1); // 获取
		System.out.println(department2.getName());
		System.out.println(department2.getEmployees());

		session2.getTransaction().commit();
		session2.close();
	}

	// 测试查询缓存
	// 当使用Query.list()时,默认不会使用二级缓存
	@Test
	public void testQueryCache() throws Exception {
		// ===================== 第1个Session
		Session session = sessionFactory.openSession();
		session.beginTransaction();

		List<Employee> list = session.createQuery("FROM Employee e WHERE e.id<10").list();
		System.out.println(list);

		Employee employee5 = (Employee) session.get(Employee.class, 5);
		System.out.println(employee5);

		session.getTransaction().commit();
		session.close();

		// ===================== 第2个Session
		Session session2 = sessionFactory.openSession();
		session2.beginTransaction();

		List<Employee> list2 = session2.createQuery("FROM Employee e WHERE e.id<10").list();
		System.out.println(list2);

		session2.getTransaction().commit();
		session2.close();
	}

	// 测试查询缓存
	// 在使用HQL方式的查询时,如果用iterate()方法,就会使用缓存。
	// 因为这个方法是先查询所有符合条件的id集合,再一个一个的按id查找数据,就能用上缓存了。
	// 但这个方法会有N+1次查询的问题,提升性能有限,不太常用。
	@Test
	public void testQueryCache2() throws Exception {
		// ===================== 第1个Session
		Session session = sessionFactory.openSession();
		session.beginTransaction();

		Iterator<Employee> iterator = session.createQuery("FROM Employee e WHERE e.id<8").iterate();
		while (iterator.hasNext()) {
			Employee e = iterator.next();
			System.out.println(e);
		}

		Employee employee5 = (Employee) session.get(Employee.class, 5);
		System.out.println(employee5);

		session.getTransaction().commit();
		session.close();
		System.out.println("\n------------------\n");

		// ===================== 第2个Session
		Session session2 = sessionFactory.openSession();
		session2.beginTransaction();

		Iterator<Employee> iterator2 = session2.createQuery("FROM Employee e WHERE e.id<10").iterate();
		while (iterator2.hasNext()) {
			Employee e = iterator2.next();
			System.out.println(e);
		}

		session2.getTransaction().commit();
		session2.close();
	}

	@Test
	public void testQueryCache3() throws Exception {
		// ===================== 第1个Session
		Session session = sessionFactory.openSession();
		session.beginTransaction();

		List list = session.createQuery("FROM Employee e WHERE e.id<18")//
				.setCacheable(true)// 是否使用查询缓存,需要在hibernate.cfg.xml中开启查询缓存才行
				.list();
		System.out.println(list);

		session.getTransaction().commit();
		session.close();
		System.out.println("\n------------------\n");

		// ===================== 第2个Session
		Session session2 = sessionFactory.openSession();
		session2.beginTransaction();

		List list2 = session2.createQuery("FROM Employee e WHERE e.id<18")//
				.setCacheable(true)// 是否使用查询缓存
				.list();
		System.out.println(list2);

		session2.getTransaction().commit();
		session2.close();
	}

	// 测试Update与 Delete格式的HQL语对二级缓存的影响
	// 会让二级缓存中相关的数据失效,下次使用这些数据时会重新到数据库中加载
	@Test
	public void testUpdateTimestampCache() throws Exception {
		// ===================== 第1个Session
		Session session = sessionFactory.openSession();
		session.beginTransaction();

		// 先获取
		Employee employee = (Employee)session.get(Employee.class, 1);
		System.out.println(employee.getName());
		
		// 再直接更新DB
		session.createQuery("UPDATE Employee e SET e.name=? WHERE id=?")//
			.setParameter(0, "测试")//
			.setParameter(1, 1)//
			.executeUpdate();// 执行
		
		// 再显示这个员工的名称
		System.out.println(employee.getName());

		session.getTransaction().commit();
		session.close();
		System.out.println("\n------------------\n");

		// ===================== 第2个Session
		Session session2 = sessionFactory.openSession();
		session2.beginTransaction();

		Employee employee2 = (Employee)session2.get(Employee.class, 1);
		System.out.println(employee2.getName());


		session2.getTransaction().commit();
		session2.close();
	}
}


在hibernate中有一个线程的session,使用的是getCurrentSession方法

要使用也是要在cfg.xml中配置绑定的线程信息

<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
	<session-factory name="foo">
		<!-- 配置数据库信息 --> 
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		<property name="connection.url">jdbc:mysql:///hibernate_20120328</property>
		<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="connection.username">root</property>
		<property name="hibernate.connection.password">root</property>

		<!-- 其他配置 -->
		<property name="hibernate.show_sql">true</property>
		<property name="hibernate.format_sql">false</property>
		<property name="hbm2ddl.auto">update</property>
	
		<!-- 当配置为thread时,SessionFactory的getCurrentSession()方法就能使用了 -->
		<property name="current_session_context_class">thread</property>
	
		
	
	
	
	</session-factory>
</hibernate-configuration>

在类中实现

package hibernate_a_example;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class App2 {

	private static SessionFactory sessionFactory = new Configuration()//
			.configure("hibernate_a_example/myhibernate.cfg.xml")//
			.buildSessionFactory();

	// 要想使用SessionFactory.getCurrentSession()方法
	// 需要在Hibernate主配置文件中配置current_session_context_class项。
	// getCurrentSession()方法:
	// >> 去指定的上下文中(如thread)查找绑定的Session对象,如果有就返回。
	// >> 如果没有,就创建一个并绑定好,然后返回
	// >> openSession()只是开启一个新的Session,不会做绑定和查找操作。
	@Test
	public void testSession() throws Exception {
		Session session1 = sessionFactory.getCurrentSession();
		Session session2 = sessionFactory.getCurrentSession();

		System.out.println(session1 != null); // true
		System.out.println(session1 == session2); // true
	}

	// 当使用getCurrentSession时,Hibernate会在提交或回滚后自动的关闭Session
	@Test
	public void testSessionClose() throws Exception {
		Session session = sessionFactory.getCurrentSession();
		session.beginTransaction();

		System.out.println("使用Session做XXX操作");

		session.getTransaction().commit();
		 //session.close(); // 当使用getCurrentSession时,就不能再自己关闭了
	}

	@Test
	public void testSession2() throws Exception {
		Session session1 = sessionFactory.openSession();
		Session session2 = sessionFactory.openSession();

		System.out.println(session1 != null); // true
		System.out.println(session1 == session2); // false
	}

	@Test
	public void testSession3() throws Exception {
		Session session2 = sessionFactory.getCurrentSession();
		Session session1 = sessionFactory.openSession();

		System.out.println(session1 != null); // true
		System.out.println(session1 == session2); // false
	}
}

在使用了二级缓存,session所要查询的对象在一个事务中是同一个事务,除非提交了事务或者关闭了事务,会产生另一个session对象,opensession产生的session对象每次产生的都是新的session,在一个事务中不是唯一

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值