zoukankan      html  css  js  c++  java
  • Hibernate缓存

    缓存:

      是计算机领域的概念,它介于应用程序和永久性数据存储源之间。

    缓存:

      一般人的理解是在内存中的一块空间,可以将二级缓存配置到硬盘。用白话来说,就是一个存储数据的容器。我们关注的是,哪些数据需要被放入二级缓存。

    缓存作用:

      降低应用程序直接读写数据库的频率,从而提高程序的运行性能。缓存中的数据是数据存储源中数据的拷贝。缓存的物理介质通常是【内存】。

    缓存:是计算机领域的概念,它介于应用程序和永久性数据存储源之间。

    缓存:一般人的理解是在内存中的一块空间,可以将二级缓存配置到硬盘。用白话来说,就是一个存储数据的容器。我们关注的是,哪些数据需要被放入二级缓存。

    缓存作用:降低应用程序直接读写数据库的频率,从而提高程序的运行性能。缓存中的数据是数据存储源中数据的拷贝缓存的物理介质通常是【内存】

      

    Hibernate的缓存一般分为3

      一级缓存

      二级缓存

      查询缓存

    04.一级缓存

    01.Session内的缓存即一级缓存,内置且不能被卸载,一个事务内有效。在这个空间存放了相互关联的Java对象,这种位于Session缓存内的对象也别称为持久化对象Session负责根据持久化对象的状态变化来同步更新数据库。

    02.Session为应用程序提供了管理缓存的方法:

      evict(Object o)

      clear()

    03.金牌结论一级缓存

         一级缓存的生命周期session的生命周期一致,当前session一旦关闭,一级缓存就消失了,因此一级缓存也叫session级的缓存事务级缓存,一级缓存只存实体对象,它不会缓存一般的对象属性(查询缓存可以),即当获得对象后,就将该对象缓存起来,如果在同一session中再去获取这个对象时,它会先判断在缓存中有没有该对象的id,如果有则直接从缓存中获取此对象,反之才去数据库中取,取的同时再将此对象作为一级缓存处理。

    以下方法支持一级缓存:金牌结论

      * get() 
           * load() 
           * iterate(查询实体对象) 
    其中 Query Criterialist() 只会缓存,但不会使用缓存(除非结合查询缓存)。

     

    05.二级缓存(面试题)

    开发中的用途没有面试带来作用大。

    二级缓存是进程(N个事务)或集群范围内的缓存,可以被所有的Session共享,在多个事务之间共享

    二级缓存是可配置的插件

    01.二级缓存的配置使用(ehcache缓存)

     *1.引入如下jar包。

          ehcache-1.2.3.jar  核心库

          backport-util-concurrent.jar  

          commons-logging.jar

       *2.配置Hibernate.cfg.xml开启二级缓存

       <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>元素的子元素下添加chche子节点,但该配置仅会缓存对象的简单属性,若希望缓存集合属性中的元素,必须在set元素中添加<cache>子元素

             <class name="Student" table="STUDENT">

             <cache usage="read-write"/>

       方案二:在大配置文件(hibernate.cfg.xml)中配置

           位置有限定

         <class-cache usage="read-write" class="cn.happy.entity.Student"/>

        <collection-cache usage="read-write" collection=""/>

       *5.src下添加ehcache.xml文件,从etc获取文件即可。

      解析 :出现如下错误因为没有添加二级缓存所需jar

      org.hibernate.HibernateException: could not instantiate RegionFactory [org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge]

      结果

      011.Hibernate5中使用idea的maven模板配置二级缓存

        1.引入pom的依赖节点

      2.Hibernate.cfg.xml中引入二级缓存和工厂的属性配置

      3.指定要缓存的类

      在Hibernate.cfg.xml

     

      4.src,但是maven目录下咱们要放在resource目录下。

      5.测试类

    02.二级缓存原理

    注意:如果缓存中的数据采用对象的散装数据形式,那么当不同的事务到缓存中查询OID1Customer对象时,获得的是Customer对象的散装数据,每个事务都必须分别根据散装数据重新构造出Customer实例,也就是说,每个事务都会获得不同的Customer对象。

    二级缓存分为:(面试 提薪 1-2K ) 缓存算法  

           类级别缓存区

           集合级别缓存区

           更新时间戳  

           查询缓存

       01.测试二级缓存  数据散装  的特点

       案例:

     public class H_01DataBulkTest {
       @Test
       public void testBulk(){
           Session session = HibernateUtil.getSession();
           Transaction tx=session.beginTransaction();
           Dept dept = (Dept)session.get(Dept.class,1);
           System.out.println(dept);
           
           Dept dept2 = (Dept)session.get(Dept.class,1);
           System.out.println(dept2);
           tx.commit();
           
           Session session2 = HibernateUtil.getSession();
           Transaction tx2=session2.beginTransaction();
           Dept dept3 = (Dept)session2.get(Dept.class,1);
           System.out.println(dept3);
           tx2.commit();
       }
    }

    结果:

    二级缓存散装数据原理图  

    解析:每次从二级缓存中取出的对象,都是一个新的对象。

     02.测试类级别的二级缓存只适用于getload获取数据,对query接口的list()可以将数据放置到类级别的缓存中,但不能使用query接口的list()从缓存中获取数据。

      Session session = HibernateUtil.getSession();
           Transaction tx=session.beginTransaction();
     List<Dept> list = session.createQuery("from Dept").list();
             System.out.println(list.get(0).getDeptName());
             tx.commit();
             
            Session session2 = HibernateUtil.getSession();
            Transaction tx2=session2.beginTransaction();
            List<Dept> list2 = session2.createQuery("from Dept").list();
            System.out.println(list2.get(0).getDeptName());
            tx2.commit();
            
            Session session3 = HibernateUtil.getSession();
            Transaction tx3=session3.beginTransaction();
            Dept dept = (Dept)session3.get(Dept.class,1);
            System.out.println(dept);

    生成SQL如下图:

    03.测试iterator()方法可以读取二级缓存中的数据

     Iterator<Dept> iterate = session.createQuery("from Dept").iterate();
           while (iterate.hasNext()) {
               Dept dd = iterate.next();
               System.out.println(dd.getDeptName());
           }
           tx.commit();
           System.out.println("================================");
           Session session2 = HibernateUtil.getSession();
            Transaction tx2=session2.beginTransaction();
           Iterator<Dept> iterate2 = session2.createQuery("from Dept").iterate();
           while (iterate2.hasNext()) {
               Dept dept = iterate2.next();
               System.out.println(dept.getDeptName());
           }
           tx2.commit();

    04.集合级别的缓存区

     @Test
           public void testCache(){
               Session session = HibernateUtil.getSession();
               Transaction tx=session.beginTransaction();
               Dept dept = (Dept)session.load(Dept.class,1);
               System.out.println(dept.getEmps().size());
               tx.commit();
               
               System.out.println("========================");
               Session session2 = HibernateUtil.getSession();
               Transaction tx2=session2.beginTransaction();
               Dept dept2 = (Dept)session2.load(Dept.class,1);
               //System.out.println(dept2.getEmps().size());
               for (Emp emp : dept2.getEmps()) {
                  System.out.println(emp.getEmpName());
               }
               tx2.commit();
         }
      

     HIbernate大配置中配置不同,生成的SQL语句不同

    <class-cache    usage="read-write" class="cn.happy.manytoonesingle.Dept"/>
     <collection-cache    usage="read-write" collection="cn.happy.manytoonesingle.Dept.emps"/>

    结果如下:

    <class-cache    usage="read-write" class="cn.happy.manytoonesingle.Dept"/>
    <class-cache    usage="read-write" class="cn.happy.manytoonesingle.Emp"/>
     <collection-cache    usage="read-write" collection="cn.happy.manytoonesingle.Dept.emps"/>

    结果:

    金牌结论 

        二级缓存也称进程级的缓存或SessionFactory级的缓存,二级缓存可以被所有session共享,二级缓存的生命周期和SessionFactory的生命周期一致。hibernate为实现二级缓存,只提供二级缓存的接口供第三方实现。二级缓存也是缓存实体对象,原理和方法都与一级缓存差不多,只是生命周期有所差异。

        * get() 
        * load() 
        * iterate(查询实体对象) 
    其中 Query Criterialist() 只会缓存,但不会使用缓存(除非结合查询缓存)。

    03.query 的list()和iterate()区别 (面试题)

       解析:

    1.返回的类型不一样,list返回List,iterate返回Iterator,
    2.获取数据的方式不一样,list会直接查数据库,iterate会先到数据库中把id都取出来,然后真正要遍历某个对象的时候先到缓存中找,如果找不到,id为条件再发一条sql到数据库,这样如果缓存中没有数据,则查询数据库的次数为n+1
    3.iterate会查询2级缓存,list 只会缓存,但不会使用缓存(除非结合查询缓存)。
    4.list中返回的List中每个对象都是原本的对象,iterate中返回的对象是代理对象

    二级缓存并发访问策略

    部门

    图书分类

    角色分配

    权限管理

    进销存:

    结论:隔离级别越高,性能越低。

    04.N+1问题

    06.查询缓存

    1,查询是数据库技术中最常用的操作,Hibernate为查询提供了缓存,用来提高查询速度,优化查询性能

    相同HQL语句检索结果的缓存!

    2,查询缓存依赖于二级缓存

       查询缓存是针对普通属性结果集的缓存,对实体对象的结果集只缓存id(其id不是对象的真正id可以看成是HQL或者SQL语句,它与查询的条件相关即where后的条件相关,不同的查询条件,其缓存的id也不一样)。查询缓存的生命周期,当前关联的表发生修改或是查询条件改变时,那么查询缓存生命周期结束,它不受一级缓存和二级缓存生命周期的影响,要想使用查询缓存需要手动配置如下

    * hlibernate.cfg.xm文件中启用查询缓存,如: 
        <property name="hibernate.cache.use_query_cache">true</property>
        * 程序中必须手动启用查询缓存,如: 
        query.setCacheable(true); 
    其中 Query Criterialist() 就可利用到查询缓存了。

    @Test
           public void testCache(){
               Session session = HibernateUtil.getSession();
               Transaction tx=session.beginTransaction();
                List<Dept> list = session.createQuery("from Dept").setCacheable(true).list();
                System.out.println(list.get(0).getDeptName());
                
               tx.commit();
               
               Session session2 = HibernateUtil.getSession();
               Transaction tx2=session2.beginTransaction();
               List<Dept> list2 = session2.createQuery("from Dept").setCacheable(true).list();
                System.out.println(list.get(0).getDeptName());
               tx2.commit();
         }

    结果:

    总结:

         不要想当然的以为缓存可以提高性能,仅仅在你能够驾驭它并且条件合适的情况下才是这样的hibernate的二级缓存限制还是比较多的。在不了解原理的情况下乱用,可能会有1+N的问题。不当的使用还可能导致读出脏数据 如果受不了hibernate的诸多限制,那么还是自己在应用程序的层面上做缓存吧。 

         在越高的层面上做缓存,效果就会越好。就好像尽管磁盘有缓存,数据库还是要实现自己的缓存,尽管数据库有缓存,咱们的应用程序还是要做缓存。因为底层的缓存它并不知道高层要用这些数据干什么,只能做的比较通用,而高层可以有针对性的实现缓存,所以在更高的级别上做缓存,效果也要好些吧。

          缓存是位于应用程序与物理数据源之间,用于临时存放复制数据的内存区域,目的是为了减少应用程序对物理数据源访问的次数,从而提高应用程序的运行性能
        重点:Hibernate在查询数据时,首先到缓存中去查找,如果找到就直接使用,找不到的时候就会从物理数据源中检索,所以,把频繁使用的数据加载到缓存区后,就可以大大减少应用程序对物理数据源的访问,使得程序的运行性能明显的提升

  • 相关阅读:
    cf D. Vessels
    cf C. Hamburgers
    zoj 3758 Singles' Day
    zoj 3777 Problem Arrangement
    zoj 3778 Talented Chef
    hdu 5087 Revenge of LIS II
    zoj 3785 What day is that day?
    zoj 3787 Access System
    判断给定图是否存在合法拓扑排序
    树-堆结构练习——合并果子之哈夫曼树
  • 原文地址:https://www.cnblogs.com/fl72/p/9890648.html
Copyright © 2011-2022 走看看