`

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 part 14:查询及数据库并发事务

    7. **Query缓存和第二级缓存**:为了提高性能,Hibernate可以配置使用查询缓存和第二级缓存。查询缓存存储查询结果,而第二级缓存则存储整个对象或集合。 8. **并发问题处理**:死锁、脏读、不可重复读和幻读是并发...

    Hibernate Part 3:核心API和常量配置

    7. **Constants Configuration**:常量配置可能包括缓存级别、二级缓存配置、实体的默认状态(如是否自动提交)等,这些配置可以显著影响性能。 8. **Entity Mapping**:介绍了如何通过XML或注解将Java类映射到...

    Hibernate part 8:一对多关联关系映射

    - **缓存**:可以使用`@Cacheable`和`@Cache`注解启用二级缓存,提高性能。 - **多表查询**:通过HQL(Hibernate Query Language)或JPA的Criteria API,可以方便地执行涉及多个表的查询。 - **反向引用**:在子...

    孙卫琴精通hibernate part2

    - Hibernate提供了第一级缓存和第二级缓存,用于提高数据访问速度。本章会讲解它们的工作原理、配置和使用,以及如何集成第三方缓存系统如 EhCache 和 Infinispan。 7. **Chapter 11:事务管理** - 事务是数据库...

    孙卫琴精通hibernate part3

    3. **缓存策略**: Hibernate支持一级缓存(Session级别)和二级缓存(SessionFactory级别)。理解何时使用一级缓存和二级缓存,以及它们的工作原理,对于提升应用程序性能至关重要。 4. **关联映射**: Hibernate...

    精通hibernate(part 2)共分4个part (孙卫琴)

    Hibernate的缓存分为一级缓存和二级缓存两部分: - **一级缓存**:也称为Session级别的缓存,是默认开启的。当Session关闭后,该缓存中的数据就会被清除。 - **二级缓存**:也称为SessionFactory级别的缓存,它不是...

    Hibernate程序高手秘笈.part10-11.rar

    1. **二级缓存**:在这一部分,作者会详细讲解如何配置和使用Hibernate的二级缓存,包括EHCache和Infinispan,以及它们在提高应用程序性能方面的作用。 2. **查询缓存**:查询缓存可以存储查询结果,避免重复执行...

    Hibernate程序高手秘笈.part04-06.rar

    8. **缓存机制**:Hibernate的缓存策略,包括一级缓存(Session级别的)和二级缓存(SessionFactory级别的),以及第三方缓存集成,如 EhCache。 9. **事务管理**:介绍Hibernate的事务处理,包括编程式和声明式...

    精通 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二级缓存技术,...

    精通hibernate(part 4)共分4个part (孙卫琴)

    6. **Cache**:缓存机制用于提高应用程序性能,Hibernate支持一级缓存和二级缓存。 7. **Entity Manager**:Java Persistence API (JPA)引入的概念,为开发者提供了一组统一的接口,用于管理实体对象的生命周期。 ...

    Hibernate程序高手秘笈.part01-03.rar

    8. Cache机制:解释Hibernate的缓存策略,包括第一级缓存和第二级缓存,以及如何配置和优化缓存以提高系统性能。 9. 性能优化:讨论如何通过合理的设计和配置提升Hibernate应用的性能,包括延迟加载、批处理和连接...

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

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

    Hibernate程序高手秘笈.part07-09.rar

    5. **缓存机制**:讨论了Hibernate的缓存层次结构,包括一级缓存(Session缓存)和二级缓存(SessionFactory缓存),以及第三方缓存实现,如Ehcache和Infinispan。 6. **事务管理**:讲解了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 运行本章的...

    精通hibernate(part 1)共分4个part (孙卫琴)

    - **缓存机制**:介绍Hibernate的一级缓存和二级缓存,以及如何利用它们优化性能。 - **懒加载与立即加载**:解释这两种加载策略的区别及其应用场景。 - **多对多关联**:介绍如何在Hibernate中实现多对多关联,...

Global site tag (gtag.js) - Google Analytics