Hibernate旅程(八)Hibernate缓存机制--二级缓存

Hibernate二级级缓存


上篇介绍了Hibernate一级缓存,主要是session缓存,session生命周期结束,缓存也就结束。二级缓存相对于一级缓存来说是一个范围更广阔一些,就比你住的地方周围有多个小卖铺(session缓存),和一个大型超市,原料加工厂送货的时候送小卖铺一份的同时,必然送一份到超市。而给第二个小卖铺送一份的同时,也送给超市一份,这个超市就是我们的SessionFactoryhibernate二缓存的又称为“SessionFactory的缓存缓存的生命周期和SessionFactory(线程安全,一个数据库对应一个,重量级)的生命周期一致,所以SessionFactory可以管理二级缓存。

下面来看session控制的二级缓存。


二级缓存配置

1、          需要引入第三方的jar包,hibernateCglib.jar

2、          在缓存的配置文件来控制缓存,我们可以拷贝hibernate已有项目中的ehcache.xml配置文件到自己的项目中。通过这个文件,我们可以对二级缓存进行设置,例如缓存的时间,缓存的代销,缓存间隔多长时间自动被清掉,缓存超时间直接缓存到磁盘指定的位置上等设置。

3、          hibernate.cfg.xml文件中加入缓存产品提供商。            <propertyname="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

4、          启用二级缓存,设置为true,默认是true,添加上有助于我们手动关闭和开启二级缓存。<propertyname="hibernate.cache.use_second_level_cache">true</property>

5、          指定哪些实体类使用二级缓存。

方法一:在对应实体的.hbm.xml文件中设置,<cacheusage="read-only"/>这样如果我们想要知道二百个映射文件哪些使用了二级缓存,就要查看二百个文件,所以我们可以把对实体加入二级缓存的策略放到hibernate.cfg.xml进行配置。也就是方法二。

方法二:处于好管理的目的我们把哪个实体使用二级缓存的配置放到hibernate.cfg.xml文件中。例如执行把student实体加入二级缓存策略。       <!--

                                 指定Student使用二级缓存

                           -->

                    <class-cacheclass="com.bjpowernode.hibernate.Student"usage="read-only"/>

注意:缓存策略通常采用read-onlyread-write

缓存原则;通常是读大于写的数据进行缓存。

 


开启二级缓存在两个session中使用两次load()进行查询

代码如下所示。

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


打印结果如下图所示。


由此可知,虽然我们使用的是两个session,但第二次查询的时候没有再向数据库发出查询语句。也就是第一次查询的时候放入session的同时也放入SessionFactory缓存中一份,而第二个session再查询的时候,就直接从二级缓存中取出就可以了。


开启二级缓存在两个session中使用两次get()进行查询。

代码就是把上述代码load方法改动为get方法。

运行结果如下所示。


load一样,对于sessionFactory级别的缓存,第二次查询时就不再向数据库发出查询sql命令。



开启二级缓存,在两个session中发出load查询,采用SessionFactory管理二级缓存

代码如下所示。

/**
    * 开启二级缓存
    * 
    * 在两个session中发load查询,采用SessionFactory管理二级缓存
    */
   public voidtestCache3() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Studentstudent = (Student)session.load(Student.class, 1);
         System.out.println("student.name=" +student.getName());
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
     
      //管理二级缓存 (evict清除的意思)
      //HibernateUtils.getSessionFactory().evict(Student.class);
      HibernateUtils.getSessionFactory().evict(Student.class, 1);
     
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Studentstudent = (Student)session.load(Student.class, 1);
        
         //会发出查询语句,因为二级缓存中的数据被清除了
         System.out.println("student.name=" +student.getName());
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
   }


显示结果如下所示。


 

根据显示结果可知,在两个session中发出load查询,第一次放入session缓存同时放入了二级缓存sessionFactory中。在第二个session中,首先使用SessionFactory对二级缓存管理,使用evict()方法清除二级缓存,所以第二个session采用load查询时,需要重新向数据库发送sql命令。


一级缓存和二级缓存交互

 

代码如下所示。

public voidtestCache4() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         //禁止将一级缓存中的数据放到二级缓存中。缓存模式设置为忽略。
         session.setCacheMode(CacheMode.IGNORE);
         Studentstudent =(Student)session.load(Student.class, 1);
         System.out.println("student.name=" + student.getName());
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
 
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Studentstudent = (Student)session.load(Student.class, 1);
        
         //会发出查询语句,因为禁止了一级缓存和二级缓存的交互,一级缓存没有放到二级缓存中。
         System.out.println("student.name=" +student.getName());
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
   }


  显示结果如下所示。


从上图可以看出,首先我们开启session的事务,然后设置了当写入session缓存中的同时不写入二级缓存,session.setCacheMode(CacheMode.IGNORE),这样第二个session再查询的时候就不能从二级缓存中找到相应的内容,仍需向数据库发出sql请求。



大批量数据的添加。

当添加或更新大批量数据的时候,为了防止缓存中数据量过大,我们可以设置删除session一级缓存,如果此时开启二级缓存,那么也会同样再二级缓存中存放一份,这样的话很可能会导致缓存的溢出,所以对于大数据来说,如果放入了一级缓存中,就应该禁止再放入二级缓存中。

代码如下所示。

/**
    * 大批量的数据添加
    */
   public voidtestCache5() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
        
         //禁止一级缓存和二级缓存交互
         session.setCacheMode(CacheMode.IGNORE);
         for (int i=0;i<100; i++) {
            Studentstudent = new Student();
            student.setName("张三" +i);
            //一级缓存放一份,二级缓存也放一份。
            session.save(student);
            //每20条更新一次
            if (i %20 == 0) {
                session.flush();
                //清除缓存的内容
                //只清除了一级缓存中的内容,没有清除一级缓存中的内容。如果数据量过大,一样溢出。
                //大于大数据量来说,如果配置了一级缓存的话,就应该禁止再放入二级缓存中。
                session.clear();
            }
         }
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
   }    


控制台打印sql如下图所示。

Hibernate旅程(八)Hibernate缓存机制--二级缓存_第1张图片

 

 


Hibernate二级缓存总结

从上可知,二级缓存时比一级缓存作用域更大,是在整个应用程序中。一级缓存是不能被卸载的,是必需的,不允许也无法卸载,它是事务范围的缓存。而二级缓存是可配置的,可卸载的,SessionFactory生命周期和应用程序整个过程对应,就有可能出现并发问题。

什么样的数据适合放到二级缓存中?

1、          很少被修改的数据

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

3、          不会被并发的数据

4、          常量数据

 

什么样的数据适不合放到二级缓存中?

1、          经常被修改的数据。

2、          绝对不允许并发的数据。

3、          与其他应用共享的数据。

 

 

你可能感兴趣的:(hibernate二级缓存)