MyBatis~基于SqlSession的一级缓存和基于namespace的二级缓存

本文介绍了MyBatis的一级缓存和二级缓存概念及工作原理,通过示例展示了如何开启和使用。一级缓存默认开启,基于SqlSession,而二级缓存基于namespace,可配置在全局和映射文件中。文章通过多线程测试,解释了增删改操作如何影响缓存,并强调了实体类需实现Serializable接口以避免报错。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 我设定二个线程使用同一个sqlsession去查同一条信息,会发现他只会在数据库中查找一次, 也就是说第二次查找是在一级缓存中查找的

@org.junit.Test

public void selectById2() throws InterruptedException {

SqlSession sqlSession = DBUtil.getSqlSession();

UserDao mapper = sqlSession.getMapper(UserDao.class);

System.out.println(mapper.selectUserById(99));

CountDownLatch countDownLatch = new CountDownLatch(1);

Thread thread = new Thread(new Service(sqlSession, countDownLatch));

thread.start();

countDownLatch.await();

System.out.println(“关闭sqlSession”);

sqlSession.close();

}

public class Service implements Runnable {

private SqlSession sqlSession;

private CountDownLatch countDownLatch;

public Service(SqlSession sqlSession, CountDownLatch countDownLatch) {

this.sqlSession = sqlSession;

this.countDownLatch = countDownLatch;

}

@Override

public void run() {

System.out.println(“额外线程开始执行”);

UserDao mapper = sqlSession.getMapper(UserDao.class);

System.out.println(mapper.selectUserById(99));

System.out.println(“额外线程执行结束”);

countDownLatch.countDown();

}

}

在这里插入图片描述

  • 如果我在进行来此查找之前进行一次修改查找, 就会刷新缓冲区, 那么第二次查找就会在数据库中查找

@org.junit.Test

public void selectById() {

SqlSession sqlSession = DBUtil.getSqlSession();

UserDao mapper = sqlSession.getMapper(UserDao.class);

System.out.println(mapper.selectUserById(99));

System.out.println(“******* 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 *************************”);

System.out.println(mapper.update(99));

System.out.println(“修改完毕”);

System.out.println(mapper.selectUserById(99));

sqlSession.close();

}

在这里插入图片描述

  • 注意事项
  1. 在一个sqlsession关闭之前, 进行俩次相同内容的查询就会在日志中发现是走的缓存

  2. 如果俩次查询的内容不一样, 肯定不会走缓存区找数据, 还是执行俩次的数据库查询

  3. 增删改可能会影响原来的数据, 所以会刷新缓存, 也就是只要再俩次查询中间执行了数据库的增删改操作, 即使你俩次查询的是相同的内容, 第二次查询还是会走数据库去查询

  4. 如果执行了手动清理缓存, 也就是sqlsession.clearcache方法,第二次就会去在数据库中查询

  5. 如果关闭了这个sqlsqlsession, 就会关闭一级缓存, 即使查询俩次相同的内容还是去数据库中去查询俩次

  6. 注意一级缓存默认是开始的, 不能关闭, 只在一次sqlsession关闭之前有效

  7. 一级缓存相当于是一个map, 查到就放到一个map中, 只要进行了更新任何数据的操作, 就会刷新map中的数据,也就是全删掉

[](()二级缓存演示


  • 二级缓存也叫命名空间全局缓存

基于namespace级别的缓存, 也就是基于一个sql映射文件的缓存,一个命名空间对应一个二级缓存

工作机制

  • 一个sqlsession查询了一条数据,这个数据会被放在当前会话的一级缓存中

  • 如果当前会话关闭了,这个会话对应的一级缓存也就结束了

  • 但是我们开启了二级缓存, 所以此时这条数据就会被放到对用的sql映射文件中的二级缓存

  • 如果在在同一个映射文件中的其他sqlsession查询信息的话, 就可以在这个二级缓存中查询信息

  • 不同的映射文件查出的数据会放在自己对应的二级缓存map中

[](()开启二级缓存

  1. 在MyBatis-config文件中使用setting开启全局缓存
  1. 在sql映射文件中插入一行代码开启二级缓存
  1. 可以在标签中设置这个操作需不需要缓存, 需不需要刷新缓存

  2. 使用俩个sqlsession 查同一条信息, 观察日志,注意二级缓存是在一级缓存死了一个才发挥作用,所以得将第一个sqlsession关闭才能看见效果

  • 注意问题需要将实体序列化,不然就会报错

public class User implements Serializable {

private int id;

private String name;

private String pwd;

}

  • 下面演示我使用俩个线程,使用俩个sqlsession, 并且在第一个sqlsession关闭后, 进行查询相同的信息

@org.junit.Test

public void selectById22() throws InterruptedException {

SqlSession sqlSession = DBUtil.getSqlSession();

SqlSession sqlSession1 = DBUtil.getSqlSession();

UserDao mapper = sqlSession.getMapper(UserDao.class);

System.out.println(mapper.selectUserById(99));

System.out.println(“关闭sqlSession”);

sqlSession.close();

CountDownLatch countDownLatch = new CountDownLatch(1);

Thread thread = new Thread(new Service(sqlSession1, countDownLatch));

thread.start();

countDownLatch.await();

System.out.println(“关闭sqlSession1”);

sqlSession1.close();

}

在这里插入图片描述

[](()小结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值