zoukankan      html  css  js  c++  java
  • MyBatis(六)缓存机制 之 二级缓存

    一、二级缓存简介

      1、简介

        (1)二级缓存(second level cache),全局作用域缓存;
        (2)二级缓存默认不开启,需要手动配置;
        (3)MyBatis 提供二级缓存的接口以及实现,缓存实现要求 POJO 实现 Serializable 接口;
        (4)二级缓存在 SqlSession 关闭或提交之后才会生效;

      2、说明

        二级缓存是全局缓存,基于 namespace 级别的缓存,一个 namespace 对应一个二级缓存;

        工作机制:

        (1)一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;

        (2)如果当前会话关闭了,一级缓存中的数据会被保存到二级缓存中,新的会话查询信息,就可以参照二级缓存中的内容;

        (3)每一个 namespace 对应一个二级缓存,不同 namespace 查出的数据会放在自己对应的缓存中(map)

    sqlSession===EmployeeMapper==>Employee
                 DepartmentMapper==>Department
    

      

    二、二级缓存的使用步骤

      1、全局配置文件中开启二级缓存

    <setting name = "cacheEnabled" value="true" /> 默认是 false(不开启)
    

      

      2、在每个 mapper.xml 中配置使用二级缓存 <cache></cache>

        二级缓存需要在 mapper.xml 中配置 <cache> 标签,所以二级缓存来说是 映射文件级别的。不管 SqlSession 是怎么创建的,只要是访问的同一个映射文件中的 SQL 语句,就可以被缓存。

      3、注意: POJO 需要实现 Serializable 接口

    三、二级缓存工作机制

      工作机制:

      1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;

      2、如果会话关闭:一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容;

      3、不同namespace查出的数据会放在自己对应的缓存中(map), 效果:数据会从二级缓存中获取,查出的数据都会被默认先放在一级缓存中。

      4、只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中;

      5、如果 sqlSession 没有关闭,还是会从一级缓存查询;

    四、二级缓存相关的属性(<cache>标签中的属性)

    <cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024" type=""></cache>

      (1)cache 开启二级缓存

      (2)eviction 缓存的回收策略

    LRU:最近最少使用的,移除最长时间不被使用的对象。
    FIFO:先进先出,按对象进入缓存的顺序来移除它们。
    SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象。
    VEAK:弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象。
    默认的是 LRU。
    

      (3)flushInterval 缓存刷新间隔,单位毫秒

          缓存多长时间清空一次,默认不清空,设置一个毫秒值

          默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
                    不设置,代表缓存永远不刷新,如果满了,使用缓存回收策略来处理。

      (4)readOnly 是否只读 true/false

        true:只读缓存:mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。
                        会给所调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。只读缓存,当获取对象时,会从缓存中给返回,一定不能修改,如果修改了,可能造成返回的对象与数据库中的记录不一致,造成脏读的现象。
        false:读写缓存:mybatis觉得获取的数据可能会被修改。
                    mybatis会利用序列化&反序列的技术克隆一份新的数据给你。安全,速度慢。
                    会返回缓存对象的拷贝(通过序列化),这会慢一些,但是安全,因此默认是 false。

      (5)size 缓存中存放多少元素,引用数据,正整数

          代表缓存最多可以存储多少个对象,太大容易导致内存溢出,还严重消耗内存;太小则没意义;

      (6)type:用来设置第三方缓存,指定自定义缓存的全类名;实现cache接口即可。

    五、代码示例

      1、使用二级缓存

        代码:

        /**
          * 二级缓存
          * @throws IOException
          */
         @Test
         public void testSecondLevelCache() throws IOException {
              SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
              SqlSession sqlSession = sqlSessionFactory.openSession();
              SqlSession sqlSession2 = sqlSessionFactory.openSession();
              try {
                   EmployeeMapperCache mapper = sqlSession.getMapper(EmployeeMapperCache.class);
                   EmployeeMapperCache mapper2 = sqlSession2.getMapper(EmployeeMapperCache.class);
    
    
                   Employee emp01 = mapper.getEmpById(1);
                   System.out.println("emp01 = " + emp01);
                   sqlSession.close();
    
                   //第二次查询是从二级缓冲中拿到的数据,并没有发送新的SQL
                   //缓存命中率 Cache Hit Ratio [com.njf.mybatis.dao.EmployeeMapperCache]: 0.5
                   Employee emp02 = mapper2.getEmpById(1);
                   System.out.println("emp02 = " + emp02);
                   sqlSession2.close();
    
                   System.out.println(emp01 == emp02);
              } finally {
                   sqlSession.close();
              }
         }

        运行结果:

      命中率是指:后面的 SQL 语句在缓存中,有多少 SQL 命中(即与缓存中的 SQL重复)
            而这里的命中率为0.5,是因为二级缓存必须在 SqlSession 关闭或提交之后才会生效,上面的代码中,sqlSession关闭后,把查询结果放在二级缓存中,这时再去查询正好命中。

      2、未开启二级缓存

        代码:

        /**
          * 未启用二级缓存
          * @throws IOException
          */
         @Test
         public void testSecondLevelCacheDisable() throws IOException {
              SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
              SqlSession sqlSession = sqlSessionFactory.openSession();
              SqlSession sqlSession2 = sqlSessionFactory.openSession();
              try {
                   DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
                   DepartmentMapper mapper2 = sqlSession2.getMapper(DepartmentMapper.class);
    
                   Department dept01 = mapper.getDeptById(1);
                   System.out.println("dept01 = " + dept01);
                   sqlSession.close();
    
                   Department dept02 = mapper2.getDeptById(1);
                   System.out.println("dept02 = " + dept02);
                   sqlSession2.close();
    
                   System.out.println(dept01 == dept02);
              } finally {
                   sqlSession.close();
                   sqlSession2.close();
              }
         }

        运行结果:

         可以看到发送了两条SQL语句,正是因为没有使用二级缓存,当第一个 sqlSession 关闭后,没有把查询结果放在二级缓存中,所以再次查询时会重新发送 SQL 语句。

  • 相关阅读:
    WinCE下SQLCE数据库开发(VS,VB.net,VC++)
    基于VC++的WinCE网口通信
    WinCE下的串口通信开发(VS2005,VB.Net,VC++)
    多线程CSerialPort类的多串口通信实现
    双T滤波电路用于PWM方式DAC的分析
    AD9516锁相环功能外接环路滤波器的设计与分析
    块结构中断有序化处理方法(一种单片机单线程方式下处理多中断的方法)
    STM32F10X固件库函数——串口清状态位函数分析
    STM32和STR71X移植uCos-II操作系统比较分析
    基于uIP和uC/OS-II嵌入式网络开发
  • 原文地址:https://www.cnblogs.com/niujifei/p/15243666.html
Copyright © 2011-2022 走看看