首页 > 编程知识 正文

mybatis一级缓存和二级缓存,cpu一级缓存和二级缓存

时间:2023-05-05 14:38:51 阅读:281711 作者:834

众所周知,Mybatis 的一级缓存是 sqlSession 级别的,二级缓存是 sqlSessionFactory 级别的。

然而,在我们的代码中,根本找不到SqlSession、sqlSessionFactory 相关的东西。那么,Mybatis 的一二级缓存该如何命中呢?

一级缓存:

默认情况下,mybatis 开启并使用了一级缓存。

/** * 开启事务,测试一级缓存效果 * 缓存命中顺序:二级缓存---> 一级缓存---> 数据库 **/@Test@Transactional(rollbackFor = Throwable.class)public void testFistCache(){ // 第一次查询,缓存到一级缓存 userMapper.selectById(1); // 第二次查询,直接读取一级缓存 userMapper.selectById(1);}

执行以上代码,虽然进行了两次查询,但最终只请求了一次数据库,显然,第二次查询命中了一级缓存,直接返回了数据。

说明一下:由于使用了数据库连接池,默认每次查询完之后自动 commite,这就导致两次查询使用的不是同一个 sqlSessioin,根据一级缓存的原理,它将永远不会生效。当我们开启了事务,两次查询都在同一个 sqlSession 中,从而让第二次查询命中了一级缓存。

二级缓存

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

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

<cache />

测试代码如下:

/** * 测试二级缓存效果 * 需要*Mapper.xml开启二级缓存 **/@Testpublic void testSecondCache(){ userMapper.selectById(1); userMapper.selectById(1);}

两次查询,最终只请求了一次数据库,显然,第二次查询直接命中了二级缓存,日志还打印了该缓存的命中率。

问题:慎用二级缓存

二级缓存的作用域是一个 namespace ( 一般情况下一个 namespace 即一个 Mapper )

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.zhengxl.mybatiscache.mapper.userMapper"></mapper>

二级缓存不建议使用,因为二级缓存有严重的使用问题:
例如:
MapperA 联合查询AB表中数据
MapperA:select from tableA left join tableB on ……
MapperB 修改了数据
MapperB:insert into tableB values ……
由于 MapperA 和 MapperB 不在同一个作用域,即使 MapperB 新增了数据,MapperA 缓存也不会刷新,造成 MapperA 查到的数据是脏数据。

当然,解决办法也是有的,可以使用 cache-ref 标签合并两个 Mapper 为同一个 namespace。

配置 UserMapper.xml

<cache-ref namespace="com.zhengxl.mybatiscache.mapper.UserOrderMapper"/>

但随着Left Join … ON 的需求变多,namespace 将变得越来越难以维护。

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

参考:
SpringBoot+Mybatis一级缓存和二级缓存详解
MySQL缓存、MyBatis缓存

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。