• mybatis的缓存机制


    一级缓存

    Mybatis存在一级缓存和二级缓存,默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存(一级缓存无法关闭,只能调整)

    1. public static void main(String[] args) throws InterruptedException {
    2. try (SqlSession sqlSession = MybatisUtil.getSession(true)){
    3. TestMapper testMapper = sqlSession.getMapper(TestMapper.class);
    4. Student student1 = testMapper.getStudentBySid(1);
    5. Student student2 = testMapper.getStudentBySid(1);
    6. System.out.println(student1 == student2);
    7. }
    8. }

    两次得到的是同一个Student对象,也就是说我们第二次查询并没有重新去构造对象,而是直接得到之前创建好的对象

    1. public static void main(String[] args) throws InterruptedException {
    2. try (SqlSession sqlSession = MybatisUtil.getSession(true)){
    3. TestMapper testMapper = sqlSession.getMapper(TestMapper.class);
    4. Student student1 = testMapper.getStudentBySid(1);
    5. testMapper.addStudent(new Student().setName("小李").setSex("男"));
    6. Student student2 = testMapper.getStudentBySid(1);
    7. System.out.println(student1 == student2);
    8. }
    9. }

    一级缓存,在进行DML操作后,会使得缓存失效,也就是说Mybatis知道我们对数据库里面的数据进行了修改,所以之前缓存的内容可能就不是当前数据库里面最新的内容了。还有一种情况就是,当前会话结束后,也会清理全部的缓存,因为已经不会再用到了。但是一定注意,一级缓存只针对于单个会话,多个会话之间不相通。

    注意:一个会话DML操作只会重置当前会话的缓存,不会重置其他会话的缓存,也就是说,其他会话缓存是不会更新的!

    二级缓存

    1. <cache
    2. eviction="FIFO"
    3. flushInterval="60000"
    4. size="512"
    5. readOnly="true"/>

    一级缓存给我们提供了很高速的访问效率,但是它的作用范围实在是有限,如果一个会话结束,那么之前的缓存就全部失效了,但是我们希望缓存能够扩展到所有会话都能使用,因此我们可以通过二级缓存来实现,二级缓存默认是关闭状态,要开启二级缓存,我们需要在映射器XML文件中添加

    1. <mapper namespace="edu.test.mapper.TestMapper">
    2. <cache
    3. eviction="FIFO"
    4. flushInterval="60000"
    5. size="512"
    6. readOnly="true"/>
    7. <resultMap id="test" type="Student">
    8. <result property="name" column="sname"/>
    9. <result column="sno" property="sno"/>
    10. <result column="sdept" property="dept"/>
    11. <result property="sex" column="ssex"/>
    12. resultMap>
    13. <select id="selectMaleStudent" resultMap="test">
    14. select * from student where ssex='男';
    15. select>
    16. mapper>

    实例

    1. public static void main(String[] args) {
    2. try (SqlSession sqlSession = MybatisUtil.getSqlSession(true)) {
    3. SqlSession sqlSession1=MybatisUtil.getSqlSession(true);
    4. TestMapper testMapper = sqlSession.getMapper(TestMapper.class);
    5. TestMapper testMapper1 = sqlSession1.getMapper(TestMapper.class);
    6. Student student1 = testMapper1.getStudent("20200512039");
    7. sqlSession1.close();
    8. Student student = testMapper.getStudent("20200512039");
    9. System.out.println(student == student1);
    10. System.out.println(student.equals(student1));
    11. }
    12. }

    输出

    1. 开始构造
    2. true
    3. true

    上面的代码中首先是第一个会话在进行读操作,完成后会结束会话,而第二个操作重新创建了一个新的会话,再次执行了同样的查询,我们发现得到的依然是缓存的结果。

    总结:二级缓存是Mapper级别的,也就是说,当一个会话结束时,它的缓存依然会存在于二级缓存中,因此如果我们再次创建一个新的会话会直接使用之前的缓存。当第一个对话没有结束时,它的一级缓存就不会写入二级缓存中,也就是说,此时第二次对话就无法访问到之前的缓存

    例子

    1. public static void main(String[] args) {
    2. try (SqlSession sqlSession = MybatisUtil.getSqlSession(true)) {
    3. SqlSession sqlSession1=MybatisUtil.getSqlSession(true);
    4. TestMapper testMapper = sqlSession.getMapper(TestMapper.class);
    5. TestMapper testMapper1 = sqlSession1.getMapper(TestMapper.class);
    6. Student student1 = testMapper1.getStudent("20200512039");
    7. Student student = testMapper.getStudent("20200512039");
    8. System.out.println(student == student1);
    9. sqlSession1.close();
    10. }
    11. }

    输出

    1. 开始构造
    2. 开始构造
    3. false

    添加了二级缓存之后,会先从二级缓存中查找数据,当二级缓存中没有时,才会从一级缓存中获取,当一级缓存中都还没有数据时,才会请求数据库

    读取顺序:二级缓存 => 一级缓存 => 数据库

    使用useCache属性来关闭缓存使用flushCache="false"在每次执行后都清空缓存,通过这这个我们还可以控制DML操作完成之后不清空缓存。

    1. <select id="getStudentBySid" resultType="Student" useCache="false" flushCache="true">
    2. select * from student where sid = #{sid}
    3. select>

    关闭Mybatis的二级缓存

    1. <settings>
    2. <setting name="cacheEnabled" value="false"/>
    3. settings>

  • 相关阅读:
    服务器64GB内存、8核CPU的MySQL 8配置参数
    【ROS2原理11】C++编程的要点
    openpnp软件的使用 - 配置自动电动飞达
    Linux内存管理(二十六):shrink_list
    【Python&语义分割】Segment Anything(SAM)模型交互式分割+掩膜保存(三)
    变电站综合自动化系统的组网与应用
    刷题知识回顾《五》二叉树的最近公共祖先
    PAT 1017 A除以B
    灯具行业MES解决方案,实现产品的正反向追溯
    什么是软件需求?以及需求的最佳实践?
  • 原文地址:https://blog.csdn.net/weixin_51992178/article/details/126307137