Mybatis 缓存

Mybatis 缓存

Mybatis 中有一级缓存和二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的。一级缓存是指 SqlSession 级别的缓存,当在同一个 SqlSession 中进行相同的 SQL 语句查询时,第二次以后的查询不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存 1024 条 SQL。二级缓存是指可以跨 SqlSession 的缓存。是 mapper 级别的缓存,对于 mapper 级别的缓存不同的sqlsession 是可以共享的。

image-20231220202746078

Mybatis 的一级缓存原理(sqlsession 级别)

第一次发出一个查询 sql,sql 查询结果写入 sqlsession 的一级缓存中,缓存使用的数据结构是一个 map。

key:MapperID+offset+limit+Sql+所有的入参

value:用户信息

同一个 sqlsession 再次发出相同的 sql,就从缓存中取出数据。如果两次中间出现 commit 操作(修改、添加、删除),本 sqlsession 中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存。

一级缓存失效的原因
  • 原因一:使用不同的SqlSession对象导致无法看到一级缓存工作。
    测试代码:
@Test
public void test002() {
   
    SqlSession sqlSession = MyBatisTools.getSqlSession();
    UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
    Users users1 = usersMapper.getUserById(1);
    System.out.println("Users1==" + users1);
    //新建了一个sqlSession 
    SqlSession sqlSession2 = MyBatisTools.getSqlSession();
    UsersMapper usersMapper2 = sqlSession2.getMapper(UsersMapper.class);
    Users users2 = usersMapper2.getUserById(1);
    System.out.println("Users2==" + users2);
    System.out.println("users1与users2是否相等:" + (users1 == users2));
    sqlSession.close();
    sqlSession2.close();
}

可以看到执行结果获取的两个对象已经不相等,一级缓存已经失效。

img

  • 原因二:在一个SqlSession使用相同条件,但是,此时在查询之间进行数据修改操作会导致一级缓存失效。
@Test
public void test003() {
   
    SqlSession sqlSession = MyBatisTools.getSqlSession();
    UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
    Users users1 = usersMapper.getUserById(1);
    System.out.println("Users1==" + users1); //两次查询中间执行数据增加、修改或删除操作 
    Users users = new Users();
    users.setName("Lisa");
    users.setPwd("123456");
    usersMapper.addUser(users);
    Users users2 = usersMapper.getUserById(1);
    System.out.println("Users2==" + users2);
    System.out.println("users1与users2是否相等:" + (users1 == users2));
    sqlSession.commit();
    sqlSession.close();
}

执行结果如下:

img

  • 原因三:在一个SqlSession使用相同查询条件此时手动刷新缓存时导致一级缓存失败。
@Test
public void test004() {
   
    SqlSession sqlSession = MyBatisTools.getSqlSession();
    UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
    Users users1 = usersMapper.getUserById(1);
    System.out.println("Users1==" + users1); 
    /手动刷新用户一级缓存, 导致用户一级缓存原有的内容消失掉
    sqlSession.clearCache();
    Users users2 = usersMapper.getUserById(1);
    System.out.println("Users2==" + users2);
    System.out.println("users1与users2是否相等:" + (users1 == users2));
    sqlSession.close();
}

img

二级缓存原理(mapper 基本)

二级缓存的范围是 mapper 级别(mapper 同一个命名空间),mapper 以命名空间为单位创建缓存数据结构,结构是 map。mybatis 的二级缓存是通过 CacheExecutor 实现的。CacheExecutor其实是 Executor 的代理对象。所有的查询操作,在 CacheExecutor 中都会先匹配缓存中是否存在,不存在则查询数据库。

key:MapperID+offset+limit+Sql+所有的入参

具体使用需要配置:

  1. Mybatis 全局配置中启用二级缓存配置
  2. 在对应的 Mapper.xml 中配置 cache 节点
  3. 在对应的 select 查询节点中添加 useCache=true
二级缓存失效的原因
  • 原因一:二级缓存进行增删改操作也会刷新二级缓存,导致二级缓存失效。
@Test
public void test006() {
   
    SqlSession sqlSession = MyBatisTools.getSqlSession();
    UsersMapper usersMapper = sqlSession.getMapper(UsersMapper.class);
    Users users1 = usersMapper.getUserById(1);
    System.out.println("Users1==" + users1);
    sqlSession.close();
    SqlSession sqlSession3 = MyBatisTools.getSqlSession();
    UsersMapper usersMapper3 = sqlSession3.getMapper(UsersMapper.class);
    Users users = new Users();
    users.setName("Lily");
    users.setPwd("123456");
    usersMapper3.addUser(users);
    sqlSession3.commit();
    sqlSession3.close();
    //新建一个sqlSession
    SqlSession sqlSession2 = MyBatisTools.getSqlSession();
    UsersMapper usersMapper2 = sqlSession2.getMapper(UsersMapper.class);
    Users users2 = usersMapper2.getUserById(1);
    System.out.println("Users2==" + users2);
    sqlSession2.close();
    System.out.println("users1与users2是否相等:" + (users1 == users2));
}

测试结果:可以看到如下图执行了两次SQL,说明二级缓存失效

image-20231220204518934

  • 原因二:使用useCache 设置禁用二级缓存。在 statement 中设置 useCache=“false”,可以禁用当前 select 语句的二级缓存,即每次都会去数据库查询。例如
<select id="getUserById" parameterType="integer" resultType="net.togogo.pojo.Users" useCache="false"> 			select * from users where id=#{id}
</select>
  • 原因三:使用flushCache=“true” 属性刷新了缓存。设置 statement 配置中的 flushCache=“true” 属性,默认情况下为 true,即刷新缓存,一般执行完 commit 操作都需要刷新缓存,flushCache=“true” 表示刷新缓存,这样可以避免增删改操作而导致的脏读问题。
<select id="findAll" resultMap="userMap" useCache="false" flushCache="true"> 
  select * from user u left join orders o on u.id = o.uid
</select>

相关推荐

  1. mybatis缓存

    2023-12-21 14:22:02       24 阅读
  2. MyBatis笔记——MyBatis缓存

    2023-12-21 14:22:02       33 阅读
  3. Mybatis缓存机制

    2023-12-21 14:22:02       68 阅读
  4. Mybatis缓存

    2023-12-21 14:22:02       59 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-21 14:22:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-21 14:22:02       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-21 14:22:02       82 阅读
  4. Python语言-面向对象

    2023-12-21 14:22:02       91 阅读

热门阅读

  1. 低代码何去何从

    2023-12-21 14:22:02       56 阅读
  2. 对于猜数字游戏改进的心得

    2023-12-21 14:22:02       58 阅读
  3. Web ML 库的Transformers.js 提供文本转语音功能

    2023-12-21 14:22:02       42 阅读
  4. npm run dev 与npm run serve的区别

    2023-12-21 14:22:02       53 阅读
  5. Mysql允许局域网或外部网络访问

    2023-12-21 14:22:02       61 阅读
  6. 八股文打卡day4——计算机网络(4)

    2023-12-21 14:22:02       56 阅读
  7. jQuery实现轮播图代码

    2023-12-21 14:22:02       63 阅读
  8. VS项目 git 提交忽略文件配置

    2023-12-21 14:22:02       49 阅读
  9. 详解TensorFlow2.0 API:tf.data.Dataset

    2023-12-21 14:22:02       60 阅读
  10. 微信小程序中wx:if 和 hidden的区别

    2023-12-21 14:22:02       69 阅读
  11. 基于SpringBoot和微信小程序网上购物商城

    2023-12-21 14:22:02       70 阅读