`

Hibernate part 17:二级缓存

 
阅读更多

 

Session级别的缓存,事务范围的

SessionFactory级别的缓存,进程范围的

 

SessionFactory缓存:

内置:Hibernate自带的,只能缓存一些配置的SQL语句,如命名查询配置在*.hbm.xml中的SQL语句

外置:需要配置第三方插件使用,自己内有实现

 

二级缓存的结构



 

二级缓存提供商:

EHCache: 可作为进程范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 对 Hibernate 的查询缓存提供了支持
OpenSymphony `:可作为进程范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 提供了丰富的缓存数据过期策略, 对 Hibernate 的查询缓存提供了支持
SwarmCache: 可作为集群范围内的缓存, 但不支持 Hibernate 的查询缓存
JBossCache:可作为集群范围内的缓存, 支持 Hibernate 的查询缓存

 

二级缓存并发访问策略:

非严格读写(Nonstrict-read-write): 不保证缓存与数据库中数据的一致性. 提供 Read Uncommited 事务隔离级别, 对于极少被修改, 而且允许脏读的数据, 可以采用这种策略
读写型(Read-write): 提供 Read Commited 数据隔离级别.对于经常读但是很少被修改的数据, 可以采用这种隔离类型, 因为它可以防止脏读
事务型(Transactional): 仅在受管理环境下适用. 它提供了 Repeatable Read 事务隔离级别. 对于经常读但是很少被修改的数据, 可以采用这种隔离类型, 因为它可以防止脏读和不可重复读
只读型(Read-Only):提供 Serializable 数据隔离级别, 对于从来不会被修改的数据, 可以采用这种访问策略(很强,但是性能低

 

二级缓存的配置:

 

1、ehcache依赖jar包:ehcache-1.5.0.jar、commons-logging.jar、backport-util-concurrent.jar

 

2、在hibernate.cfg.cml配置文件中配置使用二级缓存

<property name="hibernate.cache.use_second_level_cache">true</property>

3、 配置二级缓存提供商

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

 4、配置二级缓存的并发策略

位置一:*.hbm.xml中

<hibernate-mapping>
	<class name="rock.lee.bean.Customer" table="customer" catalog="test" >
		<cache usage="read-write"/>

 位置二:hibernate.cfg.xml

		<class-cache usage="read-write" class="rock.lee.bean.Customer"/>
		<class-cache usage="read-write" class="rock.lee.bean.Order"/>
		<collection-cache usage="read-write" collection="rock.lee.bean.Customer.orders"/>

 5、配置ehcache.xml,解压ehcache-1.5.0.jar中获取

配置完成

 

案例一:证明二级缓存是存在的

	@Test
	public void test01() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		//SQL
		Customer  c1 = (Customer) session.get(Customer.class, 1);
		System.out.println(c1);
		//从一级缓存中获取
		Customer  c2 = (Customer) session.get(Customer.class, 1);
		System.out.println(c2);
		transaction.commit();//session close
		
		session = HibernateUtils.getCurrentSession();
		 transaction = session.beginTransaction();
		 //从二级缓存中获取
		Customer  c3 = (Customer) session.get(Customer.class, 1);
		System.out.println(c3);
		
		transaction.commit();
	}

 修改hibernate.cfg.xml关闭二级缓存, 再次执行查询

		<property name="hibernate.cache.use_second_level_cache">false</property>

 

案例二:类级别缓冲区的散装数据结构

在Customer类中的toString()中调用Object的toString()打印地址

@Override
	public String toString() {
		return "Customer [id=" + id + ", name=" + name + ", city=" + city+"]"
				+ super.toString();
	}

 还是运行案例一的程序,输出结果

Customer [id=1, name=林允儿, city=SH]rock.lee.bean.Customer@3003e926
Customer [id=1, name=林允儿, city=SH]rock.lee.bean.Customer@3003e926//来自一级缓存的对象
Customer [id=1, name=林允儿, city=SH]rock.lee.bean.Customer@4cf221f6//来自二级缓存的对象

 

案例三:get/load可以对二级缓存读写,Query的list对二级缓存只能写不能读

	@Test
	public void test02() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		//查询SQL,将数据写入二级缓存
		List<Customer> list = session.createQuery("from Customer").list();
		System.out.println(list.size());
                transaction.commit();// session close
		session = HibernateUtils.getCurrentSession();
		transaction = session.beginTransaction();
		//不能读取二级缓存数据,执行SQL查询,将数据写入二级缓存
		list = session.createQuery("from Customer").list();
		System.out.println(list.size());

                transaction.commit();// session close
		session = HibernateUtils.getCurrentSession();
		transaction = session.beginTransaction();
		//从二级缓存中获取
		Customer c1 = (Customer) session.get(Customer.class, 1);
		System.out.println(c1);

		transaction.commit();
	}

 

案例四:集合级别缓冲区的存在

	@Test
	public void test03() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();

		Customer c1 = (Customer) session.get(Customer.class, 1);
		System.out.println(c1.getOrders());
		
		transaction.commit();
		session = HibernateUtils.getCurrentSession();
		session.beginTransaction();
		
		Customer c2 = (Customer) session.get(Customer.class, 1);
		//通过二级换获得Order数据
		System.out.println(c2.getOrders());
		
		transaction.commit();
	}

 

案例五:集合级别缓冲区依赖类级别缓冲区

在hibernate.cfg.xml中注释掉Order类级别缓存

<!-- 		<class-cache usage="read-write" class="rock.lee.bean.Order" /> -->

 执行案例四同样的代码,如果Order类级别缓冲区关系,集合缓冲区也无法使用

	@Test
	public void test03() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();

		Customer c1 = (Customer) session.get(Customer.class, 1);
		System.out.println(c1.getOrders());
		
		transaction.commit();
		session = HibernateUtils.getCurrentSession();
		session.beginTransaction();
		
		Customer c2 = (Customer) session.get(Customer.class, 1);
		//通SQL获得数据
		System.out.println(c2.getOrders());
		
		transaction.commit();
	}

 集合级别的缓冲区只会缓存id,然后去类级别缓冲区里查询数据

 

案例六:一级缓存数据自动同步到二级缓存

@Test
	public void test04() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();

		Customer c1 = (Customer) session.get(Customer.class, 1);
		System.out.println(c1);
		//快照比对后自动更新,并且同步到二级缓存
		c1.setCity("GD");
		
		transaction.commit();
		session = HibernateUtils.getCurrentSession();
		session.beginTransaction();
		
		//从二级缓存中获取修改后的数据
		Customer c2 = (Customer) session.get(Customer.class, 1);
		System.out.println(c2);
	}

 

 案例七:将二级换数据保存到硬盘

保存到硬盘中的位置在ehcache.xml中配置

#默认目录C:\Users\ADMINI~1\AppData\Local\Temp\
  <diskStore path="java.io.tmpdir"/> 

  将D:\ehcache目录作为缓存目录,maxElementsInMemory配置为3

  <diskStore path="D:\ehcache"/>
 <defaultCache
            maxElementsInMemory="3"  内存中最大元素数量(当内存对数量超过这个数,才会缓存到硬盘)
            eternal="false"  缓存数据是否永久有效 
            timeToIdleSeconds="120" 设置对象空闲最长时间 ,超过时间缓存对象如果没用,回收
            timeToLiveSeconds="120"  设置对象存活最长时间, 无论对象是否使用,到时间回收 
            overflowToDisk="true"  当内存缓存数据达到上限,是否缓存到硬盘 
            maxElementsOnDisk="10000000"   硬盘上最大缓存对象数量 
            diskPersistent="false"   当jvm结束时是否持久化对象 true false 默认是false
            diskExpiryThreadIntervalSeconds="120" 专门用于清除过期对象的监听线程的轮询时
            memoryStoreEvictionPolicy="LRU" 
            />
 由于JUnit执行后会System.exit(0),所以磁盘文件大小为0,通过断点,让程序有时间将数据保存到磁盘,加休眠也可以
	@Test
	@SuppressWarnings("unchecked")
	public void test05() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();

		System.out.println(System.getProperty("java.io.tmpdir"));
		
		List<Order> list = session.createQuery("from Order").list();
		System.out.println(list.size());
		
		transaction.commit();
	}

 

 案例八:更新时间戳缓冲区

时间戳缓存区域存放了对于查询结果相关的表进行插入, 更新或删除操作的时间戳.  Hibernate 通过时间戳缓存区域来判断被缓存的查询结果是否过期

 

@Test
	public void test06() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();

		Customer c1 = (Customer) session.get(Customer.class, 2);
		// 不能这么修改,一级缓存会自动同步到二缓存
		// c1.setCity("BJ");

		session.createSQLQuery("update customer set city='BJ' where id=1").executeUpdate();

		transaction.commit();
		session = HibernateUtils.getCurrentSession();
		transaction = session.beginTransaction();

		//判断类别缓冲区中的时间戳和时间戳缓冲区的是否一样,不一样,重新发送SQL查询
		c1 = (Customer) session.get(Customer.class, 1);
		System.out.println(c1);

		transaction.commit();

	}

 

 案例九:Query接口的iterator(),返回迭代器代理对象,数据中只有id,在访问每个元素时,先查找二级缓存,如果找不到,生成SQL语句

	@Test
	public void test07() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();

		List<Order> list = (List<Order>) session.createQuery("from Order where id < 5").list();
		
		transaction.commit();
		session = HibernateUtils.getCurrentSession();
		transaction = session.beginTransaction();
		
		//不在缓存里的,会执行SQL查询
		Iterator<Order> iterate = session.createQuery("from Order where id <10").iterate();
		while (iterate.hasNext()) {
			Order o = (Order) iterate.next();
			System.out.println(o.getId()+"-->"+o.getAddress());
		}

	}

 

案例十:查询缓存

二级缓存查询结果,比如以OID作为key ,以对象作为Value 进行缓存 , 查询缓存 以SQL语句为key ,以查询结果作为Value

在hibernate.cfg.xml中配置开启查询缓存

	<property name="hibernate.cache.use_query_cache">true</property>

 代码中也要启用查询缓存

@Test
	public void test08() {
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();

		Query query = session.createQuery("select name from Customer");
		query.setCacheable(true);// 启用查询缓存
		List<String> list = query.list();

		transaction.commit();
		session = HibernateUtils.getCurrentSession();
		transaction = session.beginTransaction();

		//从查询缓存中获取数据,不会有SQL产生
		query = session.createQuery("select name from Customer");
		query.setCacheable(true);// 启用查询缓存
		List<String> lst = query.list();
		System.out.println(lst);

	}

 

 案例十一:二级缓存性能检测

在hibernate.cfg.xml配置开启性能检测

<property name="hibernate.generate_statistics">true</property>

 二级缓存命中率

// 二级缓存的性能监测
	public void test09() {
		Configuration configuration = new Configuration().configure();
		SessionFactory sessionFactory = configuration.buildSessionFactory();
//		 sessionFactory.getStatistics().setStatisticsEnabled(true);
		Session session = sessionFactory.getCurrentSession();
		Transaction transaction = session.beginTransaction();

		// 放入二级缓存
		Customer customer1 = (Customer) session.get(Customer.class, 1); // 不在一级缓存,不在二级缓存  miss+1
		Customer customer2 = (Customer) session.get(Customer.class, 2); // 不在一级缓存,不在二级缓存 miss+1
		Customer customer3 = (Customer) session.get(Customer.class, 2); // 在一级缓存找到,hit和miss都不+1
		
		transaction.commit();
		session = sessionFactory.getCurrentSession();
		transaction = session.beginTransaction();

		// 读二级缓存
		Customer customer4 = (Customer) session.get(Customer.class, 1); // 在二级缓存找到hit+1
		Customer customer5 = (Customer) session.get(Customer.class, 2); // 在二级缓存找到 hit+1
		

		transaction.commit();
		// 监测
		System.out.println("命中次数: " + sessionFactory.getStatistics().getSecondLevelCacheHitCount()); // 命中次数
		System.out.println("MISS次数:" + sessionFactory.getStatistics().getSecondLevelCacheMissCount()); // 丢失次数

	}

 

 

 

 

 

 

 

 

 

 

 

  • 大小: 71.4 KB
分享到:
评论

相关推荐

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

     22.4 管理Hibernate的第二级缓存  22.4.1 配置进程范围内的第二级缓存  22.4.2 配置集群范围内的第二级缓存  22.4.3 在应用程序中管理第二级缓存  22.4.4 Session与第二级缓存的交互模式  22.5 运行本章的...

    08.拓薪教育-hibernate4.3的hibernate.cfg.xml基本配置.part2

    hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate高级映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,...

    08.拓薪教育-hibernate4.3的hibernate.cfg.xml基本配置.part1

    hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate高级映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,...

    05.拓薪教育-hibernate4.3环境搭建上.part1

    hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate高级映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part4

     22.4 管理Hibernate的第二级缓存  22.4.1 配置进程范围内的第二级缓存  22.4.2 配置集群范围内的第二级缓存  22.4.3 在应用程序中管理第二级缓存  22.4.4 Session与第二级缓存的交互模式  22.5 运行本章的...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part3

     22.4 管理Hibernate的第二级缓存  22.4.1 配置进程范围内的第二级缓存  22.4.2 配置集群范围内的第二级缓存  22.4.3 在应用程序中管理第二级缓存  22.4.4 Session与第二级缓存的交互模式  22.5 运行本章的...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part1.rar

     22.4 管理Hibernate的第二级缓存  22.4.1 配置进程范围内的第二级缓存  22.4.2 配置集群范围内的第二级缓存  22.4.3 在应用程序中管理第二级缓存  22.4.4 Session与第二级缓存的交互模式  22.5 运行本章的...

    02.拓薪教育-hibernate4.3-orm剖析.part2

    hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate高级映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,...

    04.拓薪教育-hibernate4.3官方核心包介绍.part1

    hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate高级映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,...

    06.拓薪教育-hibernate4.3环境搭建中.part1

    hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate高级映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,...

    06.拓薪教育-hibernate4.3环境搭建中.part2

    hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate高级映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,...

    05.拓薪教育-hibernate4.3环境搭建上.part2

    hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate高级映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,...

    04.拓薪教育-hibernate4.3官方核心包介绍.part2

    hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate高级映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,...

    02.拓薪教育-hibernate4.3-orm剖析.part1

    hibernate.cfg.xml配置,hbm.xml映射文件详解,主键生成策略使用,PO对象状态及状态的转换分析、一级缓存,Hibernate数据检索技术,Hibernate高级映射技术,Hibernate多表联合查询, Hibernate二级缓存技术,...

    Struts2 + Spring3 + Hibernate3.5 整合(实际使用项目,version3).part1

    此项目整合了目前主流和最前源的web开发技术:采用ehcache实现二级缓存(包含查询缓存);用sf4j及logback(log4j的升级版)记录日志;proxool(据说是dbcp和c3p0三者中最优秀的)做连接池;使用jquery的ajax实现仿...

    Struts2 + Spring3 + Hibernate3.5 整合(实际使用项目,version3).part3

    此项目整合了目前主流和最前源的web开发技术:采用ehcache实现二级缓存(包含查询缓存);用sf4j及logback(log4j的升级版)记录日志;proxool(据说是dbcp和c3p0三者中最优秀的)做连接池;使用jquery的ajax实现仿...

    基于java的企业级应用开发:RESTful支持.ppt

    PART 1 END * * 1.根据客户编号查询客户信息 根据客户编号查询客户信息主要是通过查询客户表中的主键(这里表示唯一的客户编号)来实现的。 2.根据客户名模糊查询客户...二级缓存 学习案例 案例代码 接下来,将采用RES

    Spring in Action(第二版 中文高清版).part2

    1.3.3 企业级应用中的依赖注入 1.4 应用AOP 1.4.1 AOP介绍 1.4.2 AOP使用 1.5 小结 第2章 基本Bean装配 2.1 容纳你的Bean 2.1.1 BeanFactory介绍 2.1.2 使用应用上下文 2.1.3 Bean的生命 2.2 创建Bean ...

    Spring in Action(第二版 中文高清版).part1

    1.3.3 企业级应用中的依赖注入 1.4 应用AOP 1.4.1 AOP介绍 1.4.2 AOP使用 1.5 小结 第2章 基本Bean装配 2.1 容纳你的Bean 2.1.1 BeanFactory介绍 2.1.2 使用应用上下文 2.1.3 Bean的生命 2.2 创建Bean ...

    Spring3.x企业应用开发实战(完整版) part1

    17.4.5 使用Hibernate二级缓存 17.5 对持久层进行测试 17.5.1 配置Unitils测试环境 17.5.2 准备测试数据库及测试数据 17.5.3 编写DAO测试基类 17.5.4 编写BoardDao测试用例 17.6 服务层开发 17.6.1 UserService的...

Global site tag (gtag.js) - Google Analytics