Hibernate的二级缓存

来源:互联网 时间:1970-01-01


Hibernate二级缓存:
二级缓存也称位进程级缓存或者sessionFactory级缓存,二级缓存可以被所有的session共享

二级缓存的配置和使用:
*将echcache.xml(这个文件在hibernate代码包中的etc 目录下)拷贝到src目录下
*开启二级缓存 修改hibernate.cfg.xml文件
<property>true</property>
*指定缓存产品提供商,修改hibernate.cfg.xml文件
<property>org.hibernate.cache.EhCacheProvider</property>
*指定哪些类使用二级缓存:
* 在映射文件中采用<cache usage=""> 标签
* 在hibernate.cfg.xml中配置
<class-cache usage="read-only"/>
我推荐优先使用<read-only>
1. <read-only>
如果你的应用程序只需读取一个持久化类的实例,而无需对其修改, 那么就可以对其进行只读 缓存。这是最简单,也是实用性最好的方法。
甚至在集群中,它也能完美地运作。
2. read/write
如果应用程序需要更新数据,那么使用读/写缓存 比较合适。 如果应用程序要求“序列化事务”的隔离级别(serializable transaction
isolation level), 那么就决不能使用这种缓存策略。如果在JTA环境中使用缓存,你必须指定hibernate.transaction.manager_lookup_
class属性的值, 通过它,Hibernate才能知道该应用程序中JTA的TransactionManager的具体策略。 在其它环境中,你必须保证在Session.close()
、或Session.disconnect()调用前, 整个事务已经结束。 如果你想在集群环境中使用此策略,你必须保证底层的缓存实现支持锁定(locking)。Hibernate
内置的缓存策略并不支持锁定功能
3. nonstrict read/write
如果应用程序只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离, 那么比较适合使用非严格读/写
缓存策略。如果在JTA环境中使用该策略, 你必须为其指定hibernate.transaction.manager_lookup_class属性的值, 在其它环境中,你必须保证在
Session.close()、或Session.disconnect()调用前, 整个事务已经结束


二级缓存的是缓存实体对象的:
了解一级缓存的交互(session.setCacheMode())
主要是 CacheMode.NORMAL
CacheMode.PUT
CacheMode.GET
具体常见HibernateReference
有如下2个类 :

 public class Clazz { private Integer id; private String name; private Set<Student> students=new HashSet<Student>(); } public class Student { private Integer id; private String name; private Clazz clazz;}


映射文件为(我们对students类设置缓存):
 <class table="t_clazz"> <id> <generator ></generator> </id> <property></property> <set inverse="true"> <key column="clazz"/> <one-to-many /> </set> </class><class table="t_student"> <!-- <cache usage="read-only"/>--> <id> <generator ></generator> </id> <property></property> <many-to-one cascade="save-update"></many-to-one> </class>

Hibernate 配置文件:
<hibernate-configuration><session-factory> <property>com.mysql.jdbc.Driver</property> <property>jdbc:mysql://localhost:3306/hibernate_cache_level_2</property> <property>root</property> <property>123456</property> <property>org.hibernate.dialect.MySQLDialect</property> <property>true</property> <!-- 开启二级缓存 hibernate默认就是开启的 --> <property>true</property> <!-- 指定缓存产品提供商 --> <property>org.hibernate.cache.EhCacheProvider</property> <mapping resource="com/june/hibernate/Clazz.hbm.xml"/> <mapping resource="com/june/hibernate/Student.hbm.xml"/> <!-- 我推荐在此设置二级缓存 而不是在具体的类配置文件中设置 因为在此设置会对非常清楚的了解 那些是设了二级缓存的 那些是没有设的--> <class-cache usage="read-only"/></session-factory></hibernate-configuration>


测试用例:
 package com.june.hibernate;import junit.framework.TestCase;import org.hibernate.CacheMode;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;public class CacheLevel2Test extends TestCase{/** * 开启2个session分别调用load */ public void testLoad(){ Session session=null; Transaction tx=null; try{ //第一个session session=HibernateUtil.getSession(); tx=session.beginTransaction(); Student student1=(Student)session.load(Student.class,1); System.out.println("student1.name="+student1.getName()); tx.commit(); }catch(Exception e){ e.printStackTrace(); tx.rollback(); }finally{ HibernateUtil.colseSession(session); } try{ //第二个session session=HibernateUtil.getSession(); tx=session.beginTransaction(); Student student1=(Student)session.load(Student.class,1); //不会发出session 因为开启了二级缓存 session共享二级缓存 // load()方法也使用二级缓存 System.out.println("student1.name="+student1.getName()); tx.commit(); }catch(Exception e){ e.printStackTrace(); tx.rollback(); }finally{ HibernateUtil.colseSession(session); } }/** * 开启2个session分别调用get() */ public void testGet(){ Session session=null; Transaction tx=null; try{ //第一个session session=HibernateUtil.getSession(); tx=session.beginTransaction(); Student student1=(Student)session.get(Student.class,1); System.out.println("student1.name="+student1.getName()); tx.commit(); }catch(Exception e){ e.printStackTrace(); tx.rollback(); }finally{ HibernateUtil.colseSession(session); } try{ //第二个session session=HibernateUtil.getSession(); tx=session.beginTransaction(); Student student1=(Student)session.get(Student.class,1); //也不会发出session 因为开启了二级缓存 session共享二级缓存 //get()也使用二级缓存 System.out.println("student1.name="+student1.getName()); tx.commit(); }catch(Exception e){ e.printStackTrace(); tx.rollback(); }finally{ HibernateUtil.colseSession(session); } }/** * 开启2个session分别调用load 用sessionFactory 清除二级缓存 */ public void testLoad2(){ Session session=null; Transaction tx=null; try{ //第一个session session=HibernateUtil.getSession(); tx=session.beginTransaction(); Student student1=(Student)session.load(Student.class,1); System.out.println("student1.name="+student1.getName()); tx.commit(); }catch(Exception e){ e.printStackTrace(); tx.rollback(); }finally{ HibernateUtil.colseSession(session); } SessionFactory factory=HibernateUtil.getSessionFactory(); //管理二级缓存 //factory.evict(Student.class,1); factory.evict(Student.class); try{ //第二个session session=HibernateUtil.getSession(); tx=session.beginTransaction(); Student student1=(Student)session.load(Student.class,1); //会发出查询sql 主要是由于二级缓存中的数据被清楚啦 System.out.println("student1.name="+student1.getName()); tx.commit(); }catch(Exception e){ e.printStackTrace(); tx.rollback(); }finally{ HibernateUtil.colseSession(session); } } /** * 一级缓存和二级缓存的交互 * 默认为CacheMode.NORMAL * 即以及缓存即向二级缓存中写数据也从二级缓存中读数据 */ public void testCache(){ Session session=null; Transaction tx=null; try{ //第一个session session=HibernateUtil.getSession(); tx=session.beginTransaction(); Student student1=(Student)session.load(Student.class,1); System.out.println("student1.name="+student1.getName()); tx.commit(); }catch(Exception e){ e.printStackTrace(); tx.rollback(); }finally{ HibernateUtil.colseSession(session); } try{ //第2个session session=HibernateUtil.getSession(); //仅从二级缓存读数据 而不从二级缓存写数据 session.setCacheMode(CacheMode.GET); tx=session.beginTransaction(); Student student1=(Student)session.load(Student.class,1); //不会发出sql 语句 System.out.println("student1.name="+student1.getName()); tx.commit(); }catch(Exception e){ e.printStackTrace(); tx.rollback(); }finally{ HibernateUtil.colseSession(session); } SessionFactory factory=HibernateUtil.getSessionFactory(); try{ //第3个session session=HibernateUtil.getSession(); tx=session.beginTransaction(); Student student1=(Student)session.load(Student.class,1); // 因为session设置了CacheMode位GET 所以二级缓存中没有数据 System.out.println("student1.name="+student1.getName()); tx.commit(); }catch(Exception e){ e.printStackTrace(); tx.rollback(); }finally{ HibernateUtil.colseSession(session); } } public void testCache2(){ Session session=null; Transaction tx=null; try{ //第一个session session=HibernateUtil.getSession(); tx=session.beginTransaction(); Student student1=(Student)session.load(Student.class,1); System.out.println("student1.name="+student1.getName()); tx.commit(); }catch(Exception e){ e.printStackTrace(); tx.rollback(); }finally{ HibernateUtil.colseSession(session); } try{ //第2个session session=HibernateUtil.getSession(); //仅从二级缓写读数据 而不从二级缓读写数据 session.setCacheMode(CacheMode.PUT); tx=session.beginTransaction(); Student student1=(Student)session.load(Student.class,1); System.out.println("student1.name="+student1.getName()); tx.commit(); }catch(Exception e){ e.printStackTrace(); tx.rollback(); }finally{ HibernateUtil.colseSession(session); } SessionFactory factory=HibernateUtil.getSessionFactory(); try{ //第3个session session=HibernateUtil.getSession(); tx=session.beginTransaction(); Student student1=(Student)session.load(Student.class,1); // 因为session设置了CacheMode位GET 所以二级缓存中没有数据 System.out.println("student1.name="+student1.getName()); tx.commit(); }catch(Exception e){ e.printStackTrace(); tx.rollback(); }finally{ HibernateUtil.colseSession(session); } }} 

---------------------------------------------------------------------
在运新单元测试之前请初始化数据 初始化数据类 请参照前一篇文章的的 InitialData类
运行了以上的单元测试 我们可以对hibernate的二级缓存 就会有个比较清晰的认识



相关阅读:
Top