缓存介绍,Hibernate缓存机制实例代码解析

Hibernate缓存机制实例代码解析,hibernate缓存

本文研究的主要是Hibernate缓存机制的相关内容,具体如下。

Hibernate中提供了两级缓存,一级缓存是Session级别的缓存,它属于事务范围的缓存,该级缓存由hibernate管理,应用程序无需干预;二级缓存是SessionFactory级别的缓存,该级缓存可以进行配置和更改,并且可以动态加载和卸载,hibernate还为查询结果提供了一个查询缓存,它依赖于二级缓存;

演示项目:

Student.java:

public class Student {
 /*学生ID*/
 private int id;
 /*学生姓名*/
 private String name;
 /*学生和班级的关系*/
 private Classes classes;
 //省略setter和getter方法
}

Classes.java:

public class Classes {
 /*班级ID*/
 private int id;
 /*班级名称*/
 private String name;
 /*班级和学生的关系*/
 private Set<Student> students;
 //省略setter和getter方法
}

Student.hbm.xml:

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC  
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping package="com.lixue.bean"> 
  <class name="Student" table="t_student"> 
    <id name="id"> 
      <generator class="native"/> 
    </id> 
    <!-- 映射普通属性 --> 
    <property name="name"/> 
    <!-- 多对一 映射,在多的一端加上外键--> 
    <many-to-one name="classes" column="classesid"/> 
  </class> 
</hibernate-mapping> 

Classes.hbm.xml:

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC  
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping package="com.lixue.bean"> 
  <!-- 设置lazy为false --> 
  <class name="Classes" table="t_classes" lazy="false"> 
    <id name="id"> 
      <generator class="native"/> 
    </id> 
    <property name="name"/> 
    <!-- 一对多映射 ,inverse="true"表示交给对端维护关系--> 
    <set name="students" inverse="true"> 
       <key column="classesid"/> 
      <one-to-many class="Student"/> 
    </set> 
  </class> 
</hibernate-mapping> 

一,缓存的概念

一级缓存:

一级缓存声明周期很短和session的生命周期一致,一级缓存也叫session级的缓存或事物级缓存,一级缓存是缓存对象的,并不能缓存属性。

测试方法(在同一个session中使用load()查询两次):

/*取出来之后会放在缓存中,第二次取的时候会直接从缓存取出*/ 
      Student student = (Student)session.load(Student.class, 1); 
      System.out.println("student.name=" + student.getName()); 

      /*不会发出查询语句,load使用缓存*/ 
      student = (Student)session.load(Student.class, 1); 
      System.out.println("student.name=" + student.getName()); 

注:我们会发现,当我们第一次查询的时候,查出来的结果是会放在session即缓存即一级缓存中的。第二次load()后及时去获取值的时候也没有在发出语句到数据库中查询了,而是直接从缓存中取值了(必须是在同一session中)。

测试方法二(在同一session中):

Student student = new Student(); 
      student.setName("张三"); 
      Serializable id = session.save(student); 
      student = (Student)session.load(Student.class, id); 
      //不会发出查询语句,因为save支持缓存 
      System.out.println("student.name=" + student.getName()); 

注:调用了save()方法再使用load()去加载对象,然后真正获取name属性,但是此时并不会发出语句去查询数据库。因为save()方法也是支持缓存的。

测试大批量数据的添加:

public void testCache7() { 
    Session session = null; 
    try { 
      session = HibernateUtils.getSession(); 
      session.beginTransaction(); 
      for (int i=0; i<100; i++) { 
        Student student = new Student(); 
        student.setName("张三" + i); 
        session.save(student); 
        //每20条更新一次 
        if (i % 20 == 0) { 
          //清除缓存,调用flush之后数据就会保存到数据库 
          session.flush(); 
          //清除缓存的内容 
          session.clear(); 
        } 
      } 
      session.getTransaction().commit(); 
    }catch(Exception e) { 
      e.printStackTrace(); 
      session.getTransaction().rollback(); 
    }finally { 
      HibernateUtils.closeSession(session); 
    } 
  } 

注:

1.因为save()方法支持缓存,那就存在一个问题,如果我要同时存1000万条数据,那缓存中岂不是有1000万的缓存对象,那就很可能导致溢出。所以说Hibernate并不能很好的支持大批量数据的更新操作,但是我们也可以很灵活的处理这个问题,比如使用循环每20条数据清除一次缓存。

2.save,update,saveOrUpdate,load,get,list,iterate,lock这些方法都会将对象放在一级缓存中,一级缓存不能控制缓存的数量,所以要注意大批量操作数据时可能造成内存溢出;可以用evict,clear方法清除缓存中的内容。

缓存是位于应用程序和永久性数据存储源之间用于临时存放复制数据的内存区域,缓存可以降低应用程序之间读写永久性数据存储源的次数,从而提高应用程序的运行性能;

二级缓存:

二级缓存也称为进程级缓存或SessionFactory级缓存,二级缓存可以被所有的session缓存共享。二级缓存的生命周期和SessionFactory的生命周期一致,SessionFactory可以管理二级缓存,二级缓存的原则是当读远大于写的时候使用,二级缓存也主要是缓存实体对象的。

hibernate在查询数据时,首先会到缓存中查找,如果找到就直接使用,找不到时才从永久性数据存储源中检索,因此,把频繁使用的数据加载到缓存中,可以减少应用程序对永久性数据存储源的访问,使应用程序的运行性能得以提升;

二级缓存的配置:

1.将ehcahe.xml文件拷贝到src目录下。

2.在Hibernate.cfg.xml文件中加入缓存产品提供商,如下:

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

3.启用二级缓存(可以不显示启动,因为默认就是启用的),如下:

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

4.指定哪些实体类使用二级缓存。

5.导入缓存使用的接口jar包:liboptionalehcacheehcache-core-2.4.3.jar

ehcache.xml文件的内容:

<defaultCache 
    maxElementsInMemory="10000" 
    eternal="false" 
    timeToIdleSeconds="120" 
    timeToLiveSeconds="120" 
    overflowToDisk="true" 
    /> 

注:

1.maxElementsInMemory表示缓存中最多存放的对象。

2.eternal表示是否永远不过期(设置为false更有实际意义,如果为true的话表示永远不过期,那么下面的属性都没什么意义了)。

3.timeToIdleSecods表示一个对象第一次被访问后经过多长时间没被访问就清除。

4.timeToLiveSecods表示一个对象的存货时间。

5.overflowToDisk为true表示缓存中超出了maxElementsInMemory指定的个数就存到磁盘中。

指定溢出时保存的磁盘路径:

<diskStore path="java.io.tmpdir"/>

注:这个路径可以改。

测试方法(一级缓存的前提是必须在同一个session,现在我们使用二级缓存来看看在两个不同的session中是否存在缓存):

public void testCache1() {
 Session session = null;
 try {
  session = HibernateUtils.getSession();
  session.beginTransaction();
  Student student = (Student)session.load(Student.class, 1);
  System.out.println("student.name=" + student.getName());
  session.getTransaction().commit();
 }
 catch(Exception e) {
  e.printStackTrace();
  session.getTransaction().rollback();
 }
 finally {
  HibernateUtils.closeSession(session);
 }
 try {
  session = HibernateUtils.getSession();
  session.beginTransaction();
  Student student = (Student)session.load(Student.class, 1);
  //不会发出查询语句,因为配置二级缓存,session可以共享二级缓存中的数据 
  //二级缓存是进程级的缓存 
  System.out.println("student.name=" + student.getName());
  session.getTransaction().commit();
 }
 catch(Exception e) {
  e.printStackTrace();
  session.getTransaction().rollback();
 }
 finally {
  HibernateUtils.closeSession(session);
 }
}

注:如果配置了二级缓存,我们会发现,即使第一个session关闭了,再开启另外一个session去加载数据也不会发出语句到数据库中去查询数据,因为配置了二级缓存,它是整个sessionFactory共享的。

禁用二级缓存实现大批量数据的添加:

public void testCache5() { 
    Session session = null; 
    try { 
      session = HibernateUtils.getSession(); 
      session.beginTransaction(); 

      //禁止一级缓存和二级缓存交互 
      session.setCacheMode(CacheMode.IGNORE); 
      for (int i=0; i<100; i++) { 
        Student student = new Student(); 
        student.setName("张三" + i); 
        session.save(student); 
        //每20条更新一次 
        if (i % 20 == 0) { 
          session.flush(); 
          //清除缓存的内容 
          session.clear(); 
        } 
      } 
      session.getTransaction().commit(); 
    }catch(Exception e) { 
      e.printStackTrace(); 
      session.getTransaction().rollback(); 
    }finally { 
      HibernateUtils.closeSession(session); 
    } 
  }  

注:session.flush()表示清除一级缓存,但是我们又开起了二级缓存,save()之后也保存到了二级缓存,还是存在缓存过大导致溢出的情况。所以这种情况下我们应该禁用二级缓存:session.setCacheMode(CacheMode.IGNORE);

查询缓存:一级缓存和二级缓存都是缓存实体对象的,但是有些时候我们希望获取某些属性的时候也不要频繁的去访问数据库,而是从缓存中获取,此时我们就可以使用查询缓存。另外查询缓存对实体对象的结果集会缓存ID。查询缓存的生命周期,当关联的表发生修改,查询缓存的声明周期就结束,和session的生命周期无关。

二,缓存的范围

配置查询缓存:

1.修改hibernate.cfg.xml文件,来开启查询缓存,默认是false即不开启的,应如下设置:

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

2.必须在程序中启用,如:

query.setCacheable(true) 

测试方法:

public void testCache2() {
 Session session = null;
 try {
  session = HibernateUtils.getSession();
  session.beginTransaction();
  List names = session.createQuery("select s.name from Student s") 
                  .setCacheable(true) 
                  .list();
  for (int i=0; i<names.size(); i++) {
   String name = (String)names.get(i);
   System.out.println(name);
  }
  session.getTransaction().commit();
 }
 catch(Exception e) {
  e.printStackTrace();
  session.getTransaction().rollback();
 }
 finally {
  HibernateUtils.closeSession(session);
 }
 System.out.println("-------------------------------------------------------");
 try {
  session = HibernateUtils.getSession();
  session.beginTransaction();
  //不会发出查询语句,因为查询缓存和session的生命周期没有关系 
  List names = session.createQuery("select s.name from Student s") 
                  .setCacheable(true) 
                  .list();
  for (int i=0; i<names.size(); i++) {
   String name = (String)names.get(i);
   System.out.println(name);
  }
  session.getTransaction().commit();
 }
 catch(Exception e) {
  e.printStackTrace();
  session.getTransaction().rollback();
 }
 finally {
  HibernateUtils.closeSession(session);
 }
}

注:上述代码中,我们关闭了二级缓存,开启了查询缓存,然后查询普通属性。运行测试代码我们可以发现,在第一个session中第一次查询发出了一条语句,然后关闭了session,接着再第二个session中进行查询,我们会发现第二个session中的查询并没有发出语句,这说明查询缓存和session的生命周期没有什么关系。

hibernate.cfg.xml的缓存配置:

<!-- 设置指定二级缓存的实现接口 --> 
    <property name="hibernate.cache.region.factory_class">org.hibernate.cache.EhCacheRegionFactory</property> 
    <!-- 设置二级缓存所使用的配置文件 --> 
    <property name="net.sf.ehcache.configurationResourceName">/ehcache.xml</property> 
    <!-- 设置使用QUERY查询缓存 --> 
    <property name="hibernate.cache.use_query_cache">true</property> 

    <!-- 加载对象关系映射文件 --> 
    <mapping resource="com/lixue/bean/Classes.hbm.xml" /> 
    <mapping resource="com/lixue/bean/Student.hbm.xml" /> 

    <!-- 必须先引入资源映射文件(就是实体映射文件)后再设置有使用二级缓存的实体类 --> 
    <class-cache usage="read-only" class="com.lixue.bean.Student" /> 

缓存范围决定了缓存的生命周期,缓存范围分为3类:

总结

以上就是本文关于Hibernate缓存机制实例代码解析的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

本文研究的主要是Hibernate缓存机制的相关内容,具体如下。 演示项目: Student.java: public clas...

1>事务范围

缓存只能被当前事务访问,缓存的生命周期依赖于事务的生命周期,事务结束时,缓存的生命周期也结束了;

2>进程范围

缓存被进程内的所有事务共享,这些事务会并发访问缓存,需要对缓存采用必要的事务隔离机制,缓存的生命周期取决与进程的生命周期,进程结束,缓存的生命周期也结束了;

3>集群范围

缓存被一个或多个计算机的进程共享,缓存中的数据被复制到集群中的每个进行节点,进程间通过远程通信来保证缓存中数据的一致性;

在查询时,如果在事务范围内的缓存中没有找到,可以到进程范围或集群范围的缓存中查找,如果还没找到,则到数据库中查询;

三,Hibernate中的第一级缓存

Hibernate的一级缓存由Session提供,只存在于Session的生命周期中,当应用程序调用Session接口的save(),update(),saveOrupDate(),get(),load()或者Query和Criteria实例的list(),iterate()等方法时,如果Session缓存中没有相应的对象,hibernate就会把对象加入到一级缓存中,当session关闭时,该Session所管理的一级缓存也会立即被清除;

1,get查询测试:

1>在同一个session中发出两次get查询

[java] view plain copy

 print?图片 1图片 2

  1. <span style="font-size:18px;"><strong>  public void Query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         Student s1 = (Student)sess.get(Student.class, 2);  
  5.         System.out.println(s1.getName());  
  6.         Student s2 = (Student)sess.get(Student.class, 2);  
  7.         System.out.println(s2.getName());  
  8.         tx.commit();  
  9.         HibernateSessionFactory.closeSession();  
  10.     }</strong></span>  

上面的两次查询,第一次执行了get方法查询了数据库,产生了一条sql语句,第二次执行get方法时,由于在一级缓存中找到了该对象,因此不会查询数据库,不再发出sql语句;

2>开启两个session中发出两次get查询

[java] view plain copy

 print?图片 3图片 4

  1. <span style="font-size:18px;"><strong>        public void Query(){  
  2.         Session sess1 = HibernateSessionFactory.getSession();  
  3.         Transaction tx1 = sess1.beginTransaction();  
  4.         Student s1 = (Student)sess1.get(Student.class, 2);  
  5.         System.out.println(s1.getName());  
  6.         tx1.commit();  
  7.         HibernateSessionFactory.closeSession();  
  8.         Session sess2 = HibernateSessionFactory.getSession();  
  9.         Transaction tx2 = sess2.beginTransaction();  
  10.         Student s2 = (Student)sess2.get(Student.class, 2);  
  11.         System.out.println(s2.getName());  
  12.         tx2.commit();  
  13.         HibernateSessionFactory.closeSession();  
  14.     }</strong></span>  

上面的两次查询,两次执行get方法时都查询了数据库,产生了两条sql语句,原因在于,第一次执行get方法查询出结果后,关闭了session,缓存被清除了,第二次执行get方法时,从缓存中找不到结果,只能到数据库查询;

2,iterate查询测试

插入一个iteritor查询方式:

[java] view plain copy

 print?图片 5图片 6

  1. <span style="font-size:18px;"><strong>  public void Query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         Query query = sess.createQuery("from Student");  
  5.         Iterator iter = query.iterate();  
  6.         while(iter.hasNext()){  
  7.                System.out.println(((Student)iter.next()).getName());  
  8.         }  
  9.         tx.commit();  
  10.         HibernateSessionFactory.closeSession();  
  11.     }</strong></span>  

[java] view plain copy

 print?图片 7图片 8

  1. <span style="font-size:18px;"><strong>  public void Query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         Student s1 = (Student)sess.createQuery("from Student s where s.id = 2").iterate().next();  
  5.         System.out.println(s1.getName());  
  6.         Student s2 = (Student)sess.createQuery("from Student s where s.id = 2").iterate().next();  
  7.         System.out.println(s2.getName());  
  8.         tx.commit();  
  9.         HibernateSessionFactory.closeSession();  
  10.     }</strong></span>  

上面的代码执行后会生成三条sql语句,第一次执行iterate().next()时会发出查询id的sql语句(第一条sql语句),得到s1对象,使用s1对象获得name属性值时会发出相应的查询实体对象的sql语句(第二条sql语句),第二次执行iterate().next()时会发出查询id的sql语句(第三条sql语句),但是不会发出查询实体对象的sql语句,因为hibernate使用缓存,不会发出sql语句

3,iterate查询属性测试:

[java] view plain copy

 print?图片 9图片 10

  1. <span style="font-size:18px;"><strong>  public void Query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         String name1 = (String)sess.createQuery("select s.name from Student s where s.id = 2").iterate().next();  
  5.         System.out.println(name1);  
  6.         String name2 = (String)sess.createQuery("select s.name from Student s where s.id = 2").iterate().next();  
  7.         System.out.println(name2);  
  8.         tx.commit();  
  9.         HibernateSessionFactory.closeSession();  
  10.     }</strong></span>  

上面的代码第一次执行iterate().next()时发出查询属性的sql语句,第二次执行iterate().next()时也会发出查询属性的sql语句,这是因为iterate查询普通属性,一级缓存不会缓存,所以会发出sql;

4,在一个session中先save,再执行load查询

[java] view plain copy

 print?图片 11图片 12

  1. <span style="font-size:18px;"><strong>  public void Query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         Student s = new Student(8, "newAcc", 8, 8);  
  5.         Serializable id = sess.save(s);  
  6.         tx.commit();  
  7.         Student s1 = (Student)sess.load(Student.class, 8);  
  8.         System.out.println(s1.getName());  
  9.         HibernateSessionFactory.closeSession();  
  10.     }</strong></span>  

上面的代码执行save操作时,它会在缓存里放一份,执行load操作时,不会发出sql语句,因为save使用了缓存;


Session接口为应用程序提供了两个管理缓存的方法:

1>evict()方法:用于将某个对象从Session的一级缓存中清除;

2>clear()方法:用于将一级缓存中的所有对象全部清楚;

测试:

[java] view plain copy

 print?图片 13图片 14

  1. <span style="font-size:18px;"><strong>  public void Query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         Student s = (Student)sess.load(Student.class, 1);  
  5.         System.out.println(s.getName());  
  6.         sess.clear();//清除一级缓存中的所有对象  
  7.         Student s1 = (Student)sess.load(Student.class, 1);  
  8.         System.out.println(s1.getName());  
  9.         tx.commit();  
  10.         HibernateSessionFactory.closeSession();  
  11.     }</strong></span>  

**从上面的代码可以看出,clear方法可以管理一级缓存,一级缓存无法取消,但是可以管理,第一次执行load操作时会发出sql语句,接着由于一级缓存中的实体被清除了,因此第二次执行load操作时也会发出sql语句;

**

四,Hibernate中的第二级缓存

二级缓存是一个可插拔的缓存插件,它是由SessionFactory负责管理的;

由于SessionFactory对象的生命周期与应用程序的整个过程对应,通常一个应用程序对应一个SessionFactory,因此,二级缓存是进程范围或者集群范围的缓存;

与一级缓存一样,二级缓存也是根据对象的id来加载与缓存,当执行某个查询获得结果集为实体对象集时,hibernate就会把它们按照对象id加载到二级缓存中,在访问指定的id的对象时,首先从一级缓存中查找,找到就直接使用,找不到则转到二级缓存中查找(必须配置且启用二级缓存),如果二级缓存中找到,则直接使用,否则会查询数据库,并将查询结果根据对象的id放到缓存中;

1,常用的二级缓存插件

Hibernate的二级缓存功能是通过配置二级缓存插件来实现的,常用的二级缓存插件包括EHCache,OSCache,SwarmCache和JBossCache。其中EHCache缓存插件是理想的进程范围的缓存实现,此处以使用EHCache缓存插件为例,来介绍如何使用hibernate的二级缓存;

2,Hibernate中使用EHCache的配置

1>引入EHCache相关的jar包;

liboptionalehcache下的三个jar包;

2>创建EHCache的配置文件ehcache.xml

[html] view plain copy

 print?图片 15图片 16

  1. <span style="font-size:18px;"><strong><ehcache>  
  2.     <diskStore path="java.io.tmpdir"/>  
  3.     <defaultCache  
  4.         maxElementsInMemory="10000"  
  5.         eternal="false"  
  6.         timeToIdleSeconds="120"  
  7.         timeToLiveSeconds="120"  
  8.         overflowToDisk="true"  
  9.         />  
  10.     <cache name="sampleCache1"  
  11.         maxElementsInMemory="10000"  
  12.         eternal="false"  
  13.         timeToIdleSeconds="300"  
  14.         timeToLiveSeconds="600"  
  15.         overflowToDisk="true"  
  16.         />  
  17.     <cache name="sampleCache2"  
  18.         maxElementsInMemory="1000"  
  19.         eternal="true"  
  20.         timeToIdleSeconds="0"  
  21.         timeToLiveSeconds="0"  
  22.         overflowToDisk="false"  
  23.         />  
  24. </ehcache></strong></span>  

在上述配置中,diskStore元素设置缓存数据文件的存储目录;defaultCache元素设置缓存的默认数据过期策略;cache元素设置具体的命名缓存的数据过期策略。每个命名缓存代表一个缓存区域,命名缓存机制允许用户在每个类以及类的每个集合的粒度上设置数据过期策略;
在defaultCache元素中,maxElementsInMemory属性设置缓存对象的最大数目;eternal属性指定是否永不过期,true为不过期,false为过期;timeToldleSeconds属性设置对象处于空闲状态的最大秒数;timeToLiveSeconds属性设置对象处于缓存状态的最大秒数;overflowToDisk属性设置内存溢出时是否将溢出对象写入硬盘;

3>在Hibernate配置文件里面启用EHCache

在hibernate.cfg.xml配置文件中,启用EHCache的配置如下:

[html] view plain copy

 print?图片 17图片 18

  1. <span style="font-size:18px;"><strong>                <!-- 启用二级缓存 -->  
  2.         <property name="hibernate.cache.use_second_level_cache">true</property>  
  3.         <!-- 设置二级缓存插件EHCache的Provider类 -->  
  4.         <property name="hibernate.cache.region.factory_class">  
  5.         org.hibernate.cache.ehcache.EhCacheRegionFactory</property></strong></span>  

4>配置哪些实体类的对象需要二级缓存,有两种方式:

1>>在实体类的映射文件里面配置

在需要进行缓存的持久化对象的映射文件中配置相应的二级缓存策略,如User,hbm.xml:

[html] view plain copy

 print?图片 19图片 20

  1. <span style="font-size:18px;"><strong><?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC  
  3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4. ";  
  5. <hibernate-mapping>  
  6.     <class name="com.hibtest1.entity.User" table="user" catalog="bookshop">  
  7.         <cache usage="read-write"/>  
  8.         <id name="id" type="java.lang.Integer">  
  9.             <column name="Id" />  
  10.             <generator class="native" />  
  11.         </id>  
  12.         <property name="loginName" type="java.lang.String">  
  13.             <column name="LoginName" length="50" />  
  14.         </property>  
  15.           
  16.     </class>  
  17. </hibernate-mapping></strong></span>  

映射文件中使用<cache>元素设置持久化类User的二级缓存并发访问策略,usage属性取值为read-only时表示只读型并发访问策略;read-write表示读写型并发访问策略;nonstrict-read-write表示非严格读写型并发访问策略;EHCache插件不支持transactional(事务型并发访问策略)。
注意:<cache>元素只能放在<class>元素的内部,而且必须处在<id>元素的前面,<cache>元素放在哪些<class>元素下面,就说明会对哪些类进行缓存;

2>>在hibernate配置文件中统一配置,强烈推荐使用这种方式:

在hibernate.cfg.xml文件中使用<class-cache>元素来配置哪些实体类的对象需要二级缓存:

[java] view plain copy

 print?图片 21图片 22

  1. <span style="font-size:18px;"><strong><span style="font-size:18px;"><strong><span style="font-size:18px;"><strong><class-cache usage="read-only" class="com.anlw.entity.Student"/></strong></span></strong></span></strong></span>  

在<class-cache>元素中,usage属性指定缓存策略,需要注意<class-cache>元素必须放在所有<mapping>元素的后面;

3,Hibernate中使用EHCache的测试:

[java] view plain copy

 print?图片 23图片 24

  1. <span style="font-size:18px;"><strong>  public void Query(){  
  2.         Session sess1 = HibernateSessionFactory.getSession();  
  3.         Student s1 = (Student)sess1.get(Student.class, 1);  
  4.         System.out.println(s1.getName());  
  5.         HibernateSessionFactory.closeSession();  
  6.         Session sess2 = HibernateSessionFactory.getSession();  
  7.         Student s2 = (Student)sess2.get(Student.class, 1);  
  8.         System.out.println(s2.getName());  
  9.         HibernateSessionFactory.closeSession();  
  10.     }</strong></span>  

上面的代码,第一次执行get方法查询出结果后,关闭了session,一级缓存被清除了,由于配置并启用了二级缓存,查询出的结果会放入二级缓存,第二次执行get方法时,首先从一级缓存中查找,没有找到,然后转到二级缓存查找,二级缓存中找到结果,就不需要从数据库查询了。

注意:在hibernate配置二级缓存时属性的顺序如下,顺序错了会空指针异常:

[java] view plain copy

 print?图片 25图片 26

  1. <span style="font-size:18px;"><strong>                <!-- 启用二级缓存 -->  
  2.         <property name="hibernate.cache.use_second_level_cache">true</property>  
  3.         <!-- 设置二级缓存插件EHCache的Provider类 -->  
  4.         <property name="hibernate.cache.region.factory_class">  
  5.         org.hibernate.cache.ehcache.EhCacheRegionFactory</property>  
  6.         <mapping class="com.anlw.entity.Student"/>  
  7.         <class-cache usage="read-only" class="com.anlw.entity.Student"/></strong></span>  

**先缓存配置,再mapping,最后calss-cache;

**

五,Hibernate中的查询缓存

对于经常使用的查询语句,如果启用了查询缓存 ,当第一次执行查询语句时,hibernate会将查询结果存储在二级缓存中,以后再次执行该查询语句时,从缓存中获取查询结果,从而提高查询性能;

hibernate的查询缓存主要是针对普通属性结果集的缓存,而对于实体对象的结果集只缓存id;

查询缓存的生命周期,若当前关联的表发生修改,那么查询缓存的生命周期结束;

1,查询缓存的配置

查询缓存基于二级缓存,使用查询缓存前,必须首先配置好二级缓存;

在配置了二级缓存的基础上,在hibernate的配置文件hibernate.cfg.xml中添加如下配置,可以启用查询缓存:

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

此外在程序中还必须手动启用查询缓存:

query.setCacheable(true);

2,测试查询缓存:

1>开启查询缓存,关闭二级缓存,开启一个session,分别调用query.list查询属性,测试前,先在先在hibernate.cfg.xml文件中开启查询缓存,关闭二级缓存,如下所示:

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

[java] view plain copy

 print?图片 27图片 28

  1. <span style="font-size:18px;"><strong>    public static void query(){  
  2.         Session sess = HibernateSessionFactory.getSession();  
  3.         Transaction tx = sess.beginTransaction();  
  4.         Query query = sess.createQuery("select s.name from Student s");  
  5.         query.setCacheable(true);  
  6.         List names = query.list();  
  7.         for(Iterator iter = names.iterator();iter.hasNext();){  
  8.             String name = (String)iter.next();  
  9.             System.out.println(name);  
  10.         }  
  11.         System.out.println("----------");  
  12.         query = sess.createQuery("select s.name from Student s");  
  13.         query.setCacheable(true);  
  14.         names = query.list();  
  15.         for(Iterator iter = names.iterator();iter.hasNext();){  
  16.             String name = (String)iter.next();  
  17.             System.out.println(name);  
  18.         }  
  19.         tx.commit();  
  20.         HibernateSessionFactory.closeSession();  
  21.     }  
  22. </strong></span>  

第二次没有去查数据库,因为启用了查询缓存;

2>开启查询缓存,关闭二级缓存,开启两个session,分别调用query.list查询属性,测试前,先在先在hibernate.cfg.xml文件中开启查询缓存,关闭二级缓存,如下所示:

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

[java] view plain copy

 print?图片 29图片 30

  1. <span style="font-size:18px;"><strong>  public static void query(){  
  2.         Session sess1 = HibernateSessionFactory.getSession();  
  3.         Transaction tx1 = sess1.beginTransaction();  
  4.         Query query = sess1.createQuery("select s.name from Student s");  
  5.         query.setCacheable(true);  
  6.         List names = query.list();  
  7.         for(Iterator iter = names.iterator();iter.hasNext();){  
  8.             String name = (String)iter.next();  
  9.             System.out.println(name);  
  10.         }  
  11.         tx1.commit();  
  12.         HibernateSessionFactory.closeSession();  
  13.         System.out.println("----------");  
  14.         Session sess2 = HibernateSessionFactory.getSession();  
  15.         Transaction tx2 = sess2.beginTransaction();  
  16.         query = sess2.createQuery("select s.name from Student s");  
  17.         query.setCacheable(true);  
  18.         names = query.list();  
  19.         for(Iterator iter = names.iterator();iter.hasNext();){  
  20.             String name = (String)iter.next();  
  21.             System.out.println(name);  
  22.         }  
  23.         tx2.commit();  
  24.         HibernateSessionFactory.closeSession();  
  25.     }</strong></span>  

第二次没有去查数据库,因为查询缓存生命周期与session生命周期无关;

3>开启查询缓存,关闭二级缓存,开启两个session,分别调用query.list查询实体对象,测试前,先在先在hibernate.cfg.xml文件中开启查询缓存,关闭二级缓存,如下所示:

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

[java] view plain copy

 print?图片 31图片 32

  1. <span style="font-size:18px;"><strong>  public static void query(){  
  2.         Session sess1 = HibernateSessionFactory.getSession();  
  3.         Transaction tx1 = sess1.beginTransaction();  
  4.         Query query = sess1.createQuery("from Student");  
  5.         query.setCacheable(true);  
  6.         List student = query.list();  
  7.         for(Iterator iter = student.iterator();iter.hasNext();){  
  8.             Student s = (Student)iter.next();  
  9.             System.out.println(s.getName()+"--"+s.getAge());  
  10.         }  
  11.         tx1.commit();  
  12.         HibernateSessionFactory.closeSession();  
  13.         System.out.println("----------");  
  14.         Session sess2 = HibernateSessionFactory.getSession();  
  15.         Transaction tx2 = sess2.beginTransaction();  
  16.         query = sess2.createQuery("from Student");  
  17.         query.setCacheable(true);  
  18.         student = query.list();  
  19.         for(Iterator iter = student.iterator();iter.hasNext();){  
  20.             Student s = (Student)iter.next();  
  21.             System.out.println(s.getName()+"--"+s.getAge());  
  22.         }  
  23.         tx2.commit();  
  24.         HibernateSessionFactory.closeSession();  
  25.     }</strong></span>  

查询结果如下:

[java] view plain copy

 print?图片 33图片 34

  1. <span style="font-size:18px;"><strong>Hibernate:   
  2.     select  
  3.         student0_.id as id1_0_,  
  4.         student0_.age as age2_0_,  
  5.         student0_.name as name3_0_   
  6.     from  
  7.         student student0_  
  8. anliwenaaa--1  
  9. test--2  
  10. ----------  
  11. Hibernate:   
  12.     select  
  13.         student0_.id as id1_0_0_,  
  14.         student0_.age as age2_0_0_,  
  15.         student0_.name as name3_0_0_   
  16.     from  
  17.         student student0_   
  18.     where  
  19.         student0_.id=?  
  20. Hibernate:   
  21.     select  
  22.         student0_.id as id1_0_0_,  
  23.         student0_.age as age2_0_0_,  
  24.         student0_.name as name3_0_0_   
  25.     from  
  26.         student student0_   
  27.     where  
  28.         student0_.id=?  
  29. anliwenaaa--1  
  30. test--2</strong></span>  

**第二次查询数据库时,会发出n条sql语句,因为开启了查询缓存,关闭了二级缓存,那么查询缓存会缓存实体对象的id,所以hibernate会根据实体对象的id去查询相应的实体,如果缓存中不存在相应的实体,那么将发出根据实体id查询的sql语句,否则不会发出sql,使用缓存中的数据;

**

4>开启查询缓存,开启二级缓存,开启两个session,分别调用query.list查询实体对象,测试前,先在先在hibernate.cfg.xml文件中开启查询缓存,开启二级缓存,如下所示:

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

代码和3>一样,但是结果不同,第二次不会发出sql,因为开启了二级缓存和缓存查询,查询缓存缓存了实体对象的id,hibernate会根据实体对象的id到二级缓存中取得相应的数据;

本文由365bet体育在线官网发布于关于计算机,转载请注明出处:缓存介绍,Hibernate缓存机制实例代码解析

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。