• 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在查询数据时,首先到缓存中去查找,如果找到就直接使用,找不到的时候就会从物理数据源中检索,所以,把频繁使用的数据加载到缓存区后,就可以大大减少应用程序对物理数据源的访问,使得程序的运行性能明显的提升

  • 相关阅读:
    php静态调用非静态方法
    phalcon 框架3.0更新时报错
    centos7.5更换docker-ce镜像源
    腾讯云更换镜像源遇到的坑
    php cli模式下调试
    审查php.ini自动分析程序
    docker WARNING: IPv4 forwarding is disabled. Networking will not work.
    git常用命令,制作缩写命令
    学习GRPC(一) 简单实现
    mac与linux服务器之间使用ssh互通有无
  • 原文地址:https://www.cnblogs.com/fl72/p/9890648.html
Copyright © 2020-2023  润新知