MyBatis 一级缓存实现详解及使用注意事项

ⅰ亾dé卋堺 提交于 2020-04-27 11:30:22

一级缓存介绍

在应用运行过程中,我们有可能在一次数据库会话中,执行多次查询条件完全相同的SQL,MyBatis提供了一级缓存的方案优化这部分场景,如果是相同的SQL语句,会优先命中一级缓存,避免直接对数据库进行查询,提高性能。具体执行过程如下图所示。

img

每个SqlSession回话中会创建Executor执行器,每个Executor执行器中有一个Local Cache。当用户发起查询时,MyBatis根据当前执行的语句生成MappedStatement,在Local Cache进行查询,如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入Local Cache,最后返回结果给用户。

一级缓存配置

我们来看看如何使用MyBatis一级缓存。开发者只需在MyBatis的配置文件中,添加如下语句,就可以使用一级缓存。共有两个选项,SESSION或者STATEMENT,默认是SESSION级别,即在一个MyBatis会话中执行的所有语句,都会共享这一个缓存。一种是STATEMENT级别,可以理解为缓存只对当前执行的这一个Statement有效。

<setting name="localCacheScope" value="SESSION"/>

一级缓存实验

开启一级缓存,范围为会话级别,调用三次getStudentById,代码如下所示:

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)); // 查询缓存
    System.out.println(studentMapper.getStudentById(1)); // 查询缓存
}
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)); // 查询数据库
    sqlSession.close();
}
public void testLocalCacheScope() 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.getStudentById(1)); // 查询数据库
    System.out.println(studentMapper.getStudentById(1)); // 查询缓存
    System.out.println(studentMapper2.updateStudentName("小岑",1)); // 更新数据
    System.out.println(studentMapper.getStudentById(1)); // 查询缓存,脏数据
    System.out.println(studentMapper2.getStudentById(1)); // 查询数据库
}

一级缓存工作流程

一级缓存执行的时序图,如下图所示。

img

总结

  1. MyBatis一级缓存的生命周期和SqlSession一致。
  2. MyBatis一级缓存内部设计简单,只是一个没有容量限定的HashMap,在缓存的功能性上有所欠缺。
  3. MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,所以建议设定缓存级别为Statement
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!