MyBatis缓存

一级缓存

  • Mybatis的一级缓存存在于sqlSession的生命周期中,在同一个SqlSession中查询时,MyBatis会把执行方法和参数通过算法 生成缓存的键值,将键值和查询结果存入一个Map对象中。如果同一个SqlSession中执行的方法和参数完全一致,就会直接去Map中的键值匹配。可以通过设置方法中的flushCache属性取消一级缓存。
  • 当执行delete、update、insert后都会清空一级缓存。

二级缓存

  • MyBatist的二级缓存非常强大,存在于SqlSessionFactory的生命周期中。当存在多个SqlSessionFactory时,它们的缓存都是绑定在各自的对象上的,缓存数据一般情况下不能相痛!只有使用如Redis这样的缓存数据库时,才能共享缓存。
使用方法:

在Mapper.xml的便签中添加
默认的二级缓存有如下的效果:

  • 映射语句中的所以SELECT语句将会被缓存。
  • 映射语句中的所以INSERT、UPDATE、DELETE语句会刷新缓存。
  • 缓存会使用Least Recently Used算法回收。
  • 根据时间表刷新,缓存不会以任何的时间顺序刷新。//只是默认的情况
  • 缓存会存储集合或对象的1024个引用。(无论方法返回的什么类型的值)
  • 缓存都会视为read/write。意味着对象检索不是共享的,而且可以安全地被调用者修改,而不干扰其他调用者或线程所做的修改。

使用方法:

  • 在接口中添加标签@CacheNamespace

或者

  • 在mapper.xml中添加

实例:


使用二级缓存:

  • 配置好二级缓存之后,当调用所以的select查询方法时,二级缓存就会开始起作用了。注意的是,由于配置的是可读可写缓存,而MyBatis使用SerializedCache序列化缓存来实现可读可写缓存类,并通过序列化和反序列化来保证通过缓存获取数据时,得到的是一个新的实例.因此,如果配置只读缓存,MyBatis就会使用Map来存储缓存值,这种情况下,从缓存里得到的都是同一个对象。
  • 因为使用可读写缓存,所以这个缓存类要求所有被序列化的对象必须实现Serializable接口。

测试代码:

    @Test
    public void testL2Cache() {
        SqlSession sqlSession = getSqlSession();
        SysRole sysRole = null;
        try {
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
            sysRole = roleMapper.selectById(1l);
            sysRole.setRoleName("new name");

            SysRole sysRole1 = roleMapper.selectById(1l);

            Assert.assertEquals("new name", sysRole1.getRoleName());
            //一级缓存,两个查询相同的对象是相同的
            Assert.assertEquals(sysRole, sysRole1);
        } finally {
            sqlSession.close();
        }
        System.out.println("开始另一个查询");

        sqlSession = getSqlSession();
        try {
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);

            SysRole sysRole1 = roleMapper.selectById(1l);

            Assert.assertEquals("new name", sysRole1.getRoleName());

            Assert.assertNotEquals(sysRole, sysRole1);

            SysRole sysRole2 = roleMapper.selectById(1l);

            // sysRole1 sysRole2是两个反序列化得到的结果,是不相同的实例
            Assert.assertNotEquals(sysRole1, sysRole2);
        } finally {
            sqlSession.close();
        }
    }

运行结果截图:


二级缓存
  • 日志中存在好几条以Cache Hit Ratio开头的语句,这行日志后面输出的值为当前执行方法的缓存命中率。但是在这个例子中并没有真正的读写安全。因为测试中加入了一行不该有的代码,sysRole.setRoleName("new name");按照常理应该更新数据,更新后会清空一级、二级缓存,这样在第二部分的代码中就不出出现查询结果的roleName都是“new name”的结果。所以想要安全使用,就要避免出现毫无意义的修改。这样就可以避免认为的脏数据,避免缓存和数据库的数据不一致。

你可能感兴趣的:(MyBatis缓存)