Mybatis的一级缓存和二级缓存
目录
- 前言
- 一级缓存
- 1、缓存级别
- 2、开启方式
- 3、缓存对象
- 4、执行过程
- 5、实验检验
- 6、注意事项
- 二级缓存
- 1、缓存级别
- 2、开启方式
- 3、缓存对象
- 4、执行过程
- 5、实验检验
- 6、注意事项
前言
MyBatis是常见的Java数据库访问层框架。在日常工作中,开发人员多数情况下是使用MyBatis的默认缓存配置,但是MyBatis缓存机制有一些不足之处,在使用中容易引起脏数据,形成一些潜在的隐患。个人在业务开发中也处理过一些由于MyBatis缓存引发的开发问题,带着个人的兴趣,来深入了解一下缓存机制
一级缓存
1、缓存级别
sqlSession级别,同一个sqlSession内共用缓存
2、开启方式
默认开启
3、缓存对象
缓存的是对象的引用,底层通过HashMap缓存结果,key为CacheKey,value为结果对象的引用
4、执行过程
在一级缓存中,当sqlSession进行查询的时候,会先去查询一级缓存,如果命中则直接返回数据,否则就去查询数据库,然后再把数据写到一级缓存中
5、实验检验
实验1:命中一级缓存
public void getStudentById() throws Exception {
SqlSession sqlSession = factory.openSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
System.out.println(studentMapper.getStudentById(1));
System.out.println(studentMapper.getStudentById(1));
}
实验2:修改操作会刷新缓存(flushCache标签默认为 true)
public void addStudent() throws Exception {
SqlSession sqlSession = factory.openSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
System.out.println(studentMapper.getStudentById(1));
System.out.println("增加了" + studentMapper.addStudent(buildStudent()) + "个学生");
System.out.println(studentMapper.getStudentById(1));
}
实验3:缓存的是对象的引用
public void getStudentById() throws Exception {
SqlSession sqlSession = factory.openSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student s = studentMapper.getStudentById(1);
System.out.println(s);
s.setName("名字已修改");
System.out.println(studentMapper.getStudentById(1));
}
6、注意事项
①当有Insert、Delete、Update语句执行的时候,会将一级缓存清空,因为他们的flushCache标签默认为 true
②显示调用sqlSession.clearCache()
③sqlSession关闭也会清空缓存
二级缓存
1、缓存级别
namespace级别,也就是说一个mapper中的所有SQLSession都共用的一个二级缓存
2、开启方式
<!--mybatis的全局设置-->
<settings>
<!--开启二级缓存,默认是开启的为true-->
<setting name="cacheEnabled" value="true"/>
</settings>
3、缓存对象
序列化后的对象数据
4、执行过程
一级缓存中,其最大的共享范围就是一个SqlSession内部,如果多个SqlSession之间需要共享缓存,则需要使用到二级缓存。
开启二级缓存后,会使用CachingExecutor装饰Executor,进入一级缓存的查询流程前,先在CachingExecutor进行二级缓存的查询,如果二级缓存未命中,则去查询一级缓存,如果一级缓存也未命中,再去查数据库,然后将结果写入一级缓存,当sqlSession关闭或者提交事务后,一级缓存就会被刷到二级缓存中。
所以数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。
5、实验检验
实验1:基于mapper级别的缓存
public void testCacheWithCommitOrClose() throws Exception {
SqlSession sqlSession1 = factory.openSession(true);
SqlSession sqlSession2 = factory.openSession(true);
StudentMapper studentMapper = sqlSession1.getMapper(StudentMapper.class);
StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);
System.out.println("studentMapper读取数据: " + studentMapper.getStudentById(1));
sqlSession1.commit();
System.out.println("studentMapper2读取数据: " + studentMapper2.getStudentById(1));
}
实验2:更新操作会刷新缓存
public void testCacheWithUpdate() throws Exception {
SqlSession sqlSession1 = factory.openSession(true);
SqlSession sqlSession2 = factory.openSession(true);
SqlSession sqlSession3 = factory.openSession(true);
StudentMapper studentMapper = sqlSession1.getMapper(StudentMapper.class);
StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);
StudentMapper studentMapper3 = sqlSession3.getMapper(StudentMapper.class);
System.out.println("studentMapper读取数据: " + studentMapper.getStudentById(1));
sqlSession1.commit();
System.out.println("studentMapper2读取数据: " + studentMapper2.getStudentById(1));
studentMapper3.updateStudentName("方方",1);
sqlSession3.commit();
System.out.println("studentMapper2读取数据: " + studentMapper2.getStudentById(1));
}
6、注意事项
①当有Insert、Delete、Update语句执行的时候,也会将二级缓存清空
②当sqlSession关闭或者提交事务后,数据会缓存到二级缓存