- 我设定二个线程使用同一个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();
}
- 注意事项
-
在一个sqlsession关闭之前, 进行俩次相同内容的查询就会在日志中发现是走的缓存
-
如果俩次查询的内容不一样, 肯定不会走缓存区找数据, 还是执行俩次的数据库查询
-
增删改可能会影响原来的数据, 所以会刷新缓存, 也就是只要再俩次查询中间执行了数据库的增删改操作, 即使你俩次查询的是相同的内容, 第二次查询还是会走数据库去查询
-
如果执行了手动清理缓存, 也就是sqlsession.clearcache方法,第二次就会去在数据库中查询
-
如果关闭了这个sqlsqlsession, 就会关闭一级缓存, 即使查询俩次相同的内容还是去数据库中去查询俩次
-
注意一级缓存默认是开始的, 不能关闭, 只在一次sqlsession关闭之前有效
-
一级缓存相当于是一个map, 查到就放到一个map中, 只要进行了更新任何数据的操作, 就会刷新map中的数据,也就是全删掉
[](()二级缓存演示
- 二级缓存也叫命名空间全局缓存
基于namespace级别的缓存, 也就是基于一个sql映射文件的缓存,一个命名空间对应一个二级缓存
工作机制
-
一个sqlsession查询了一条数据,这个数据会被放在当前会话的一级缓存中
-
如果当前会话关闭了,这个会话对应的一级缓存也就结束了
-
但是我们开启了二级缓存, 所以此时这条数据就会被放到对用的sql映射文件中的二级缓存
-
如果在在同一个映射文件中的其他sqlsession查询信息的话, 就可以在这个二级缓存中查询信息
-
不同的映射文件查出的数据会放在自己对应的二级缓存map中
[](()开启二级缓存
- 在MyBatis-config文件中使用setting开启全局缓存
- 在sql映射文件中插入一行代码开启二级缓存
-
可以在标签中设置这个操作需不需要缓存, 需不需要刷新缓存
-
使用俩个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();
}