SpringBoot+Mybatis一级缓存和二级缓存

转自:博客园 https://www.cnblogs.com/zhengxl5566/p/11868656.html
SpringBoot+Mybatis一级缓存和二级缓存详解
一、概念介绍

  • 什么是一级缓存
    在日常开发过程中,经常会有相同的sql执行多次查询的情况,mybatis提供了一级缓存来优化这些查询,避免多次请求数据库。
    一级缓存在mybatis中默认是开启的并且是session级别,它的作用域为一次sqlSession会话。
  • 什么是二级缓存
    相对于一级缓存,二级缓存的作用域更广泛,它不止局限于一个sqlSession,可以在多个sqlSession之间共享,事实上,它的作用域是namespace。
    mybatis的二级缓存默认也是开启的,但由于他的作用域是namespace,所以还需要在mapper.xml中开启才能生效。
  • 缓存的优先级
    通过mybatis发起的查询,作用顺序为:二级缓存->一级缓存->数据库 ,其中任何一个环节查到不为空的数据,都将直接返回结果
  • 缓存失效。
    当在一个缓存作用域中发生了update、insert、delete 动作后,将会触发缓存失效,下一次查询将命中数据库,从而保证不会查到脏数据。

二、代码演示

首先需要一个springboot+mybatis的dome
github:https://github.com/123ac/Springboot-Mybatis-Demo.git

创建测试类MybatisOneLvCache.java
一级缓存
默认情况下,mybatis开启并使用了一级缓存。
单元测试用例:

@SpringBootTest(classes = SpringbootMybatisDemoApplication.class) //启动项类
public class  MybatisOneLvCache {
    
    
    @Autowired
    private UserMapper userMapper;

   Logger logger=Logger.getLogger(this.getClass());


	// 为什么开启事务
	// 由于使用了数据库连接池,默认每次查询完之后自动commite,这就导致两次查询使用的不是同一个sqlSessioin,根据一级缓存的原理,它将永远不会生效。
	// 当我们开启了事务,两次查询都在同一个sqlSession中,从而让第二次查询命中了一级缓存。读者可以自行关闭事务验证此结论。
    /**
     * 开启事务,测试一级缓存效果
     * 缓存命中顺序:二级缓存---> 一级缓存---> 数据库
     **/
    @Test
    @Transactional //开启事务
    void selectById(){
    
    
        // 第一次查询,缓存到一级缓存
        UserInfo userInfo=userMapper.selectById(1);
        logger.info(userInfo);
        // 第二次查询,直接读取一级缓存
        UserInfo userInfo1=userMapper.selectById(1);
        logger.info(userInfo1);

        logger.info(userInfo==userInfo1);
        logger.info("命中了mybatis的一级缓存---》数据库只查询了一次");
    }
}

执行结果:

在这里插入图片描述

可以看到,虽然进行了两次查询,但最终只请求了一次数据库,第二次查询命中了一级缓存,直接返回了数据。
这里有两点需要说明一下:
1、为什么开启事务
由于使用了数据库连接池,默认每次查询完之后自动commite,这就导致两次查询使用的不是同一个sqlSessioin,根据一级缓存的原理,它将永远不会生效。
当我们开启了事务,两次查询都在同一个sqlSession中,从而让第二次查询命中了一级缓存。读者可以自行关闭事务验证此结论。
2、两种一级缓存模式
一级缓存的作用域有两种:session(默认)和statment,可通过设置local-cache-scope 的值来切换,默认为session。
二者的区别在于session会将缓存作用于同一个sqlSesson,而statment仅针对一次查询,所以,local-cache-scope: statment可以理解为关闭一级缓存。

二级缓存
默认情况下,mybatis打开了二级缓存,但它并未生效,因为二级缓存的作用域是namespace,所以还需要在Mapper.xml文件中配置一下才能使二级缓存生效.

  1. 单表二级缓存

    ① 对要缓存的实例化对象进行序列化

    在这里插入图片描述

    ②.下面对xxMapper.xml配置一下,让其二级缓存生效,只需加入cache标签即可

    <cache></cache>
    

    在这里插入图片描述

    新建测试类MybatisTwoLvCache.java
    单元测试用例:

    @SpringBootTest(classes = SpringbootMybatisDemoApplication.class) //启动项类
    public class MybatisTwoLvCache {
          
          
        @Autowired
        private StudentMapper studentMapper;
    
        Logger logger=Logger.getLogger(this.getClass());
    
        /**
         * 测试二级缓存效果
         * 需要*Mapper.xml开启二级缓存
         **/
        @Test
         void selectById() {
          
          
            Student student=studentMapper.selectById(1);
            logger.info(student);
            Student student1=studentMapper.selectById(1);
            logger.info(student1);
    
            logger.info(student== student1);//false的原因是由于每次序列化产生新的对象
            logger.info("命中了mybatis的二级缓存---》数据库只查询了一次");
        }
    }
    

    执行结果:

    在这里插入图片描述
    false 是因为在存入和获取的时候会对数据对象进行序列化和反序列化,返回的是一个新的对象。

    这里可以看到,第二次查询直接命中了缓存,日志还打印了该缓存的命中率。读者可以自行关闭二级缓存查看效果,通过注掉对应mapper.xml的cache标签,或者 cache-enabled: false 均可。

    注释cache标签后,运行测试类MybatisTwoLvCache。

    在这里插入图片描述

  2. 多表联查二级缓存

    接下来演示多表联查的二级缓存,

    select u.userid,u.userName,s.school,s.className from userinfo u inner join student s on s.userid=u.userid;
    

    单元测试用例:

     /**
     * 测试多表联查的二级缓存效果
     **/
    @Test
    public void testJoin(){
          
          
    
        logger.info(studentMapper.selectJion());
        logger.info(studentMapper.selectJion());
    
        Student student=new Student();
        student.setId(1);
        student.setSchool("常盘台中学");
        student.setClassName("二年级");
        studentMapper.updateById(student) ;
    
        logger.info(studentMapper.selectJion());
    }
    

    执行结果:

    在这里插入图片描述

    首先查询了两次user表,第二次命中二级缓存,然后更新user_order表,使缓存失效,第三次查询时命中数据库。

综上,mybatis的单机缓存就介绍完了,读者可以自行下载样例工程验证。

**总结:**
mybatis默认的session级别一级缓存,由于springboot中默认使用了hikariCP,所以基本没用,需要开启事务才有用。但一级缓存作用域仅限同一sqlSession内,无法感知到其他sqlSession的增删改,所以极易产生脏数据
二级缓存可通过cache-ref让多个mapper.xml共享同一namespace,从而实现缓存共享,但多表联查时配置略微繁琐。
所以生产环境建议将一级缓存设置为statment级别(即关闭一级缓存),如果有必要,可以开启二级缓存

在这里插入图片描述

注意:如果应用是分布式部署,由于二级缓存存储在本地,必然导致查询出脏数据,所以,分布式部署的应用不建议开启。

github地址:https://github.com/123ac/Mybatis.git

おすすめ

転載: blog.csdn.net/qq_40286424/article/details/108642891