时间:2020-10-16 13:04:29 | 栏目:JAVA代码 | 点击:次
Hibernate的二级缓存
一、缓存概述
缓存(Cache): 计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。缓存中的数据是数据存储源中数据的拷贝。缓存的物理介质通常是内存
hibernate中提供了两个级别的缓存
第一级别的缓存是 Session 级别的缓存,它是属于事务范围的缓存。这一级别的缓存由 hibernate 管理的,一般情况下无需进行干预
第二级别的缓存是 SessionFactory 级别的缓存,它是属于进程范围的缓存
Hibernate 的缓存可以分为两类:
内置缓存: Hibernate 自带的, 不可卸载. 通常在 Hibernate 的初始化阶段, Hibernate 会把映射元数据和预定义的 SQL 语句放到 SessionFactory 的缓存中, 映射元数据是映射文件中数据的复制, 而预定义 SQL 语句时 Hibernate 根据映射元数据推到出来的. 该内置缓存是只读的.
外置缓存(二级缓存): 一个可配置的缓存插件. 在默认情况下, SessionFactory 不会启用这个缓存插件. 外置缓存中的数据是数据库数据的复制, 外置缓存的物理介质可以是内存或硬盘
二、理解二级缓存的并发访问策略
三、配置进程范围内的二级缓存(配置ehcache缓存)
1 拷贝ehcache-1.5.0.jar到当前工程的lib目录下
依赖 backport-util-concurrent 和 commons-logging
2 开启二级缓存
<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配置
选择需要使用二级缓存的持久化类, 设置它的二级缓存的并发访问策略, <class> 元素的 cache 子元素表明 Hibernate 会缓存对象的简单属性, 但不会缓存集合属性, 若希望缓存集合属性中的元素, 必须在 <set> 元素中加入 <cache> 子元素
方法二 在hibernate.cfg.xml文件中配置(建议)
<!-- 指定使用二级缓存的类 放在maping下面 --> <!-- 配置类级别的二级缓存 --> <class-cache class="com.sihai.c3p0.Customer" usage="read-write"/> <class-cache class="com.sihai.c3p0.Order" usage="read-write"/> <!-- 配置集合级别的二级缓存 --> <collection-cache collection="com.sihai.c3p0.Customer.orders" usage="read-write"/>
5 配置ehcache默认的配置文件ehcache.xml(名字固定)(放在类路径下)
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <diskStore path="c:/ehcache"/> <defaultCache maxElementsInMemory="5" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> </ehcache>
四、 测试
package com.sihai.hibernate3.test; import java.util.Iterator; import java.util.List; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import com.sihai.hibernate3.demo1.Customer; import com.sihai.hibernate3.demo1.Order; import com.sihai.utils.HibernateUtils; public class HibernateTest6 { @Test // 查询缓存的测试 public void demo9(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); Query query = session.createQuery("select c.cname from Customer c"); // 使用查询缓存: query.setCacheable(true); query.list(); tx.commit(); session = HibernateUtils.getCurrentSession(); tx = session.beginTransaction(); query = session.createQuery("select c.cname from Customer c"); query.setCacheable(true); query.list(); tx.commit(); } @SuppressWarnings("unused") @Test // 更新时间戳 public void demo8(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); Customer customer = (Customer) session.get(Customer.class, 2); session.createQuery("update Customer set cname = '奶茶' where cid = 2").executeUpdate(); tx.commit(); session = HibernateUtils.getCurrentSession(); tx = session.beginTransaction(); Customer customer2 = (Customer) session.get(Customer.class, 2); tx.commit(); } @SuppressWarnings("all") @Test // 将内存中的数据写到硬盘 public void demo7(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); List<Order> list = session.createQuery("from Order").list(); tx.commit(); } @Test // 一级缓存的更新会同步到二级缓存: public void demo6(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); Customer customer = (Customer) session.get(Customer.class, 1); customer.setCname("芙蓉"); tx.commit(); session = HibernateUtils.getCurrentSession(); tx = session.beginTransaction(); Customer customer2 = (Customer) session.get(Customer.class, 1); tx.commit(); } @SuppressWarnings("unchecked") @Test // iterate()方法可以查询所有信息. // iterate方法会发送N+1条SQL查询.但是会使用二级缓存的数据 public void demo5(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); // N+1条SQL去查询. Iterator<Customer> iterator = session.createQuery("from Customer").iterate(); while(iterator.hasNext()){ Customer customer = iterator.next(); System.out.println(customer); } tx.commit(); session = HibernateUtils.getCurrentSession(); tx = session.beginTransaction(); iterator = session.createQuery("from Customer").iterate(); while(iterator.hasNext()){ Customer customer = iterator.next(); System.out.println(customer); } tx.commit(); } @SuppressWarnings("unchecked") @Test // 查询所有.Query接口的list()方法. // list()方法会向二级缓存中放数据,但是不会使用二级缓存中的数据. public void demo4(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); // 查询所有客户: // list方法会向二级缓存中放入数据的. List<Customer> list = session.createQuery("from Customer").list(); for (Customer customer : list) { System.out.println(customer.getCname()); } tx.commit(); session = HibernateUtils.getCurrentSession(); tx = session.beginTransaction(); // Customer customer = (Customer) session.get(Customer.class, 1);// 没有发生SQL ,从二级缓存获取的数据. // list()方法没有使用二级缓存的数据. list = session.createQuery("from Customer").list(); for (Customer customer : list) { System.out.println(customer.getCname()); } tx.commit(); } @Test // 二级缓存的集合缓冲区特点: public void demo3(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); Customer customer = (Customer) session.get(Customer.class, 1); // 查询客户的订单. System.out.println("订单的数量:"+customer.getOrders().size()); tx.commit(); session = HibernateUtils.getCurrentSession(); tx = session.beginTransaction(); Customer customer2 = (Customer) session.get(Customer.class, 1); // 查询客户的订单. System.out.println("订单的数量:"+customer2.getOrders().size()); tx.commit(); } @SuppressWarnings("unused") @Test // 配置二级缓存的情况 public void demo2(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); Customer customer1 = (Customer) session.get(Customer.class, 1);// 发送SQL. Customer customer2 = (Customer) session.get(Customer.class, 1);// 不发送SQL. System.out.println(customer1 == customer2); tx.commit(); session = HibernateUtils.getCurrentSession(); tx = session.beginTransaction(); Customer customer3 = (Customer) session.get(Customer.class, 1);// 不发送SQL. Customer customer4 = (Customer) session.get(Customer.class, 1);// 不发送SQL. System.out.println(customer3 == customer4); tx.commit(); } @SuppressWarnings("unused") @Test // 没有配置二级缓存的情况 public void demo1(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); Customer customer1 = (Customer) session.get(Customer.class, 1);// 发送SQL. Customer customer2 = (Customer) session.get(Customer.class, 1);// 不发送SQL. tx.commit(); session = HibernateUtils.getCurrentSession(); tx = session.beginTransaction(); Customer customer3 = (Customer) session.get(Customer.class, 1);// 发送SQL. tx.commit(); } }