Hibernate中的二级缓存

来源:互联网 发布:千牛与淘宝什么区别 编辑:程序博客网 时间:2024/05/22 15:24

二级缓存

1、介绍:

一、缓存

存(Cache): 计算机领域非常通用的概念。

它介于应用程序永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写硬盘(永久性数据存储源)的频率,

从而提高应用的运行性能。缓存中的数据是数据存储源中数据的拷贝。

缓存的物理介质通常是内存

       缓存:程序<--(内存)-->硬盘




二、什么是二级缓存


l  hibernate 提供缓存机制:一级缓存、二级缓存

       一级缓存:session级别缓存,在一次请求中共享数据。

       二级缓存:sessionFactory级别缓存,整个应用程序共享一个会话工厂,共享一个二级缓存。

l  SessionFactory的缓存两部分:   

内置缓存:使用一个Map,用于存放配置信息,预定义HQL语句等,提供给Hibernate框架自己使用,对外只读的。不能操作。

外置缓存:使用另一个Map,用于存放用户自定义数据。默认不开启。

外置缓存hibernate只提供规范(接口),需要第三方实现类。外置缓存有成为二级缓存。



三、二级缓存内部结构



二级就是由4部分构成

n  类级别缓存

n  集合级别缓存

n  时间戳缓存

n  查询缓存(二级缓存的第2大部分,三级缓存)


四、并发访问策略



访问策略:读写型(read-write)、只读型(read-only



五、应用场景

l  适合放入二级缓存中的数据:

       很少被修改

       不是很重要的数据, 允许出现偶尔的并发问题

l  不适合放入二级缓存中的数据:

       经常被修改

       财务数据, 绝对不允许出现并发问题

       与其他应用数据共享的数据




六、二级缓存提供商

EHCache: 可作为进程(单机)范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 对 Hibernate 的查询缓存提供了支持。--支持集群。

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

l  SwarmCache: 可作为集群范围内的缓存, 但不支持 Hibernate的查询缓存

l  JBossCache:可作为集群范围内的缓存, 支持 Hibernate 的查询缓存


X表示支持


2、配置(操作)

1.导入jar包:ehcache-1.5.0.jar/commons-logging.jar/ backport-util-concurrent.jar

2.开启二级缓存(我要使用二级缓存)

3.确定二级缓存提供商(我要使用哪个二级缓存)

4.确定需要缓存内容

       1>配置需要缓存的类

       2>配置需要缓存的集合

5.配置ehcache自定义配置文件


一、导入jar包




二、开启二级缓存


l  在hibernate.cfg.xml 配置使用二级缓存

<!-- 9.1 开启二级缓存 --><property name="hibernate.cache.use_second_level_cache">true</property>


三、确定提供商


l  hibernate.cfg.xml 配置

<!-- 9.2 提供商 --><property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>


四、确定缓存内容

一共有如下缓存:

l  在hibernate.cfg.xml 确定 类缓存 和集合缓存配置项



l  配置

<!-- 9.3 确定缓存内容 --><!-- 类缓存 --><class-cache usage="read-write" class="com.itheima.a_init.Customer"/><class-cache usage="read-write" class="com.itheima.a_init.Order"/><!-- 集合缓存 --><collection-cache usage="read-write" collection="com.itheima.a_init.Customer.orderSet"/>


五、ehcache配置文件

步骤1:从jar包复制xml文件


步骤2:将xml重命名“ehcache.xml”


步骤3:将修改后的xml,拷贝到src下


3、演示

一、证明

@Testpublic void demo01(){//1 证明二级缓存存在 // * 修改toString()// * 如果二级缓存开启,查询3 没有select语句,表示从二级缓存获得的。// * 将二级缓存关闭,查询3将触发select语句。Session s1 = factory.openSession();s1.beginTransaction();//1 查询id=1 -- 执行select (查询后,将数据存放在一级缓存,之后由一级缓存同步到二级缓存)Customer c1 = (Customer) s1.get(Customer.class, 1);System.out.println(c1);//2 查询id=1 --从一级缓存获取Customer c2 = (Customer) s1.get(Customer.class, 1);System.out.println(c2);s1.getTransaction().commit();s1.close();System.out.println("----------");Session s2 = factory.openSession();s2.beginTransaction();//3 查询id=1 -- 从二级缓存获取Customer c3 = (Customer) s2.get(Customer.class, 1);System.out.println(c3);s2.getTransaction().commit();s2.close();}


二、类缓存

l  类缓存:只存放数据

l  一级缓存:存放对象本身



@Testpublic void demo02(){//2 类缓存:只存放数据,散装数据。// * 使用默认的toString();Session s1 = factory.openSession();s1.beginTransaction();//1 查询id=1 -- 执行selectCustomer c1 = (Customer) s1.get(Customer.class, 1);System.out.println(c1);//2 查询id=1 -- 从一级缓存获取,一级缓存存放对象本身Customer c2 = (Customer) s1.get(Customer.class, 1);System.out.println(c2);s1.getTransaction().commit();s1.close();System.out.println("----------");Session s2 = factory.openSession();s2.beginTransaction();//3 查询id=1 -- 对象不一样,数据一样Customer c3 = (Customer) s2.get(Customer.class, 1);System.out.println(c3);s2.getTransaction().commit();s2.close();}


case:
package com.itheima.a_one2one;import org.hibernate.Session;import org.junit.Test;import com.itheima.domain.Address;import com.itheima.domain.Company;import com.itheima.domain.Customer;import com.itheima.utils.HibernateUtils;//演示二级缓存操作public class Demo {@SuppressWarnings("unused")@Test//演示:类缓存public void fun1(){Session session = HibernateUtils.openSession();session.beginTransaction();//------------------------------------------------Customer customer1 = (Customer) session.get(Customer.class, 1);session.clear();//清空一级缓存中的内容Customer customer2 = (Customer) session.get(Customer.class, 1);System.out.println(customer1 == customer2);//false//二级缓存在缓存数据时,并不是以对象的形式缓存. 缓存的是对象数据的散列. 每次从二级缓存拿 会在一级缓存中组装成对象.//------------------------------------------------session.getTransaction().commit();session.close(); // 游离状态}}


三、集合缓存




@Testpublic void demo03(){//3 集合缓存:只存放关联对象OID的值,如果需要数据,从类缓存中获取。// * 3.1 默认:第一条select 查询客户,第二天 select 查询客户所有订单// * 3.2 操作:在hibernate.cfg.xml 将 Order 类缓存删除// *** <!--  <class-cache usage="read-write" class="com.itheima.a_init.Order"/>-->// *** 多了10条select,通过订单的id查询订单Session s1 = factory.openSession();s1.beginTransaction();//1 查询id=1 Customer c1 = (Customer) s1.get(Customer.class, 1);System.out.println(c1);//2 获得订单for (Order o1 : c1.getOrderSet()) {System.out.println(o1);}s1.getTransaction().commit();s1.close();System.out.println("----------");Session s2 = factory.openSession();s2.beginTransaction();//3 查询id=1Customer c3 = (Customer) s2.get(Customer.class, 1);System.out.println(c3);//4 获得订单for (Order o2 : c3.getOrderSet()) {System.out.println(o2);}s2.getTransaction().commit();s2.close();}

case:
package com.itheima.a_one2one;import java.util.Iterator;import org.hibernate.Session;import org.junit.Test;import com.itheima.domain.Address;import com.itheima.domain.Company;import com.itheima.domain.Customer;import com.itheima.domain.Order;import com.itheima.utils.HibernateUtils;//演示二级缓存操作public class Demo2 {@SuppressWarnings("unused")@Test//演示:集合缓存public void fun1(){Session session = HibernateUtils.openSession();session.beginTransaction();//------------------------------------------------Customer customer1 = (Customer) session.get(Customer.class, 1);for(Order o :customer1.getOrders()){System.out.println(o.getName());}session.clear();Customer customer2 = (Customer) session.get(Customer.class, 1);Iterator<Order> it = customer2.getOrders().iterator();while(it.hasNext()){Order o = it.next();System.out.println(o.getName());}//------------------------------------------------session.getTransaction().commit();session.close(); // 游离状态}}



四、时间戳

l  时间戳:任何操作都在时间戳中记录操作时间。



@Testpublic void demo04(){//4 时间戳: 所有的操作都会在时间戳中进行记录,如果数据不一致,将触发select语句进行查询// * 修改toString()Session s1 = factory.openSession();s1.beginTransaction();//1 查询id=1 Integer cid = 1;Customer c1 = (Customer) s1.get(Customer.class, cid);System.out.println(c1);//2 绕过一级和二级缓存,修改数据库,修改客户cname=大东哥s1.createQuery("update Customer set cname = ? where cid = ?").setString(0, "大东哥").setInteger(1, cid).executeUpdate();//3打印System.out.println(c1);s1.getTransaction().commit();s1.close();System.out.println("----------");Session s2 = factory.openSession();s2.beginTransaction();//4 查询id=1  -- ?Customer c3 = (Customer) s2.get(Customer.class, 1);System.out.println(c3);s2.getTransaction().commit();s2.close();}


case:
package com.itheima.a_one2one;import java.util.List;import org.hibernate.Query;import org.hibernate.Session;import org.junit.Test;import com.itheima.domain.Customer;import com.itheima.utils.HibernateUtils;//演示二级缓存操作public class Demo4 {@Test//演示:时间戳public void fun1(){Session session = HibernateUtils.openSession();session.beginTransaction();//------------------------------------------------Customer customer1 = (Customer) session.get(Customer.class, 1);session.createQuery("update Customer set name=:name where id = :id ").setString("name", "rose").setInteger("id", 1).executeUpdate(); session.clear();Customer customer2 = (Customer) session.get(Customer.class, 1);//------------------------------------------------session.getTransaction().commit();session.close(); // 游离状态}}


五、查询缓存

l  查询缓存又称为三级缓存(民间)

l  查询缓存默认不使用。需要手动开启

l  查询缓存:将HQL语句与 查询结果进行绑定。通过HQL相同语句可以缓存内容。

       默认情况Query对象只将查询结果存放在一级和二级缓存,不从一级或二级缓存获取。

       查询缓存就是让Query可以从二级缓存获得内容。

步骤一:开启查询缓存

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

步骤二:在查询query对象,设置缓存内容(注意:存放和查询 都需要设置)

@Testpublic void demo05(){//5 查询缓存Session s1 = factory.openSession();s1.beginTransaction();//1 query查询Query q1 = s1.createQuery("from Customer");q1.setCacheable(true);List<Customer> a1 = q1.list();for (Customer c1 : a1) {System.out.println(c1);}//2 cid =1  -- 一级缓存获得Customer customer = (Customer) s1.get(Customer.class, 1);System.out.println(customer);s1.getTransaction().commit();s1.close();System.out.println("----------");Session s2 = factory.openSession();s2.beginTransaction();//2 cid =1  -- 二级缓存获得Customer customer2 = (Customer) s2.get(Customer.class, 1);System.out.println(customer2);//3 query查询Query q2 = s2.createQuery("from Customer");q2.setCacheable(true);List<Customer> a2 = q2.list();for (Customer c2 : a2) {System.out.println(c2);}s2.getTransaction().commit();s2.close();}


case:
package com.itheima.a_one2one;import java.util.List;import org.hibernate.Query;import org.hibernate.Session;import org.junit.Test;import com.itheima.domain.Customer;import com.itheima.utils.HibernateUtils;//演示二级缓存操作public class Demo3 {@Test//演示:查询缓存// 对hql语句查询的缓存public void fun1(){Session session = HibernateUtils.openSession();session.beginTransaction();//------------------------------------------------ Query query = session.createQuery("from Customer");  //使用二级(查询)缓存 // 查询时,会先从二级缓存中取结果. // 取不到就执行语句,将结果放入二级查询缓存中 query.setCacheable(true);  List<Customer> list = query.list();  session.clear();  Query query2 = session.createQuery("select c from Customer c");  query2.setCacheable(true);  List<Customer> list2 = query2.list();   //------------------------------------------------session.getTransaction().commit();session.close(); // 游离状态}}


case的配置:
<?xml version="1.0" encoding="UTF-8"?><!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 元素用于配置Hibernate中的属性 键:值 --><!-- hibernate.connection.driver_class : 连接数据库的驱动 --><property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property><!-- hibernate.connection.username : 连接数据库的用户名 --><property name="hibernate.connection.username">root</property><!-- hibernate.connection.password : 连接数据库的密码 --><property name="hibernate.connection.password">1234</property><!-- hibernate.connection.url : 连接数据库的地址,路径 --><property name="hibernate.connection.url">jdbc:mysql://localhost:3306/EE19Day04</property><property name="show_sql">true</property><property name="format_sql">true</property><property name="hbm2ddl.auto">update</property><property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property><property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property><property name="hibernate.c3p0.max_size">5</property><property name="hibernate.c3p0.min_size">2</property><property name="hibernate.current_session_context_class">thread</property><property name="hibernate.connection.isolation">4</property><!-- 配置使用二级缓存 --><property name="hibernate.cache.use_second_level_cache">true</property><!--配置二级缓存的实现类 : EHCache   --> <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property><!-- 开启查询缓存hibernate.cache.use_query_cache true --><property name="hibernate.cache.use_query_cache">true</property><mapping resource="com/itheima/domain/Customer.hbm.xml" /><mapping resource="com/itheima/domain/Order.hbm.xml" /><mapping resource="com/itheima/domain/Address.hbm.xml" /><mapping resource="com/itheima/domain/Company.hbm.xml" /><!-- 配置类缓存区中,缓存哪个类 --><class-cache usage="read-only" class="com.itheima.domain.Customer"/><class-cache usage="read-only" class="com.itheima.domain.Order"/><!-- 配置类缓存区中,缓存哪个集合collection: 完整类名.集合属性名 --><collection-cache usage="read-only" collection="com.itheima.domain.Customer.orders"/></session-factory></hibernate-configuration>


3、ehcache配置文件

l  <diskStore path="java.io.tmpdir"/>  设置临时文件存放位置。(缓存一般内存,一定程度时,写入硬盘。)


l  缓存详细设置

       <defaultCache>所有的缓存对象默认的配置

       <cachename="类"> 指定对象单独配置

l  参数设置

maxElementsInMemory="10000"  内存最大数

eternal="false"  是否永久(内存常驻留)

timeToIdleSeconds="120"

timeToLiveSeconds="120"

overflowToDisk="true"  内存满了,是否写入到硬盘

maxElementsOnDisk="10000000"  硬盘最大数

diskPersistent="false"  关闭JVM,是否将内存保存硬盘中

diskExpiryThreadIntervalSeconds="120"  轮询

memoryStoreEvictionPolicy="LRU"

       LeastRecently Used (specified as LRU).

       FirstIn First Out (specified as FIFO)

       LessFrequently Used (specified as LFU)


•   maxElementsInMemory :设置基于内存的缓存中可存放的对象最大数目

•    eternal:设置对象是否为永久的,true表示永不过期,此时将忽略timeToIdleSeconds和 timeToLiveSeconds属性; 默认值是false

•   timeToIdleSeconds:设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。当对象过期时,EHCache会把它从缓存中清除。如果此值为0,表示对象可以无限期地处于空闲状态。

•   timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。
如果此值为0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值

•   overflowToDisk:设置基于内在的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中

•    diskPersistent 当jvm结束时是否持久化对象 true false 默认是false

•   diskExpiryThreadIntervalSeconds指定专门用于清除过期对象的监听线程的轮询时间

•     memoryStoreEvictionPolicy- 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)


case:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">    <diskStore path="d:/haha"/>        <defaultCache            maxElementsInMemory="10000"            eternal="false"            timeToIdleSeconds="120"            timeToLiveSeconds="120"            overflowToDisk="true"            maxElementsOnDisk="10000000"            diskPersistent="false"            diskExpiryThreadIntervalSeconds="120"            memoryStoreEvictionPolicy="LRU"            /></ehcache>




0 0
原创粉丝点击