Mybatis缓存
约 760 字大约 3 分钟
一级缓存
mybatis的一级缓存提供SqlSession级别的查询结果缓存,也就是说在同一个SqlSession中,如果没有进行过增删改操作,相同条件的sql查询会通过一级缓存查询结果,而不用反复通过数据库执行sql。
一级缓存是全局开启的,只能通过localCacheScope这个配置修改一级缓存的作用域,可选的配置包括:
| 可选项 | 是否默认值 | 说明 |
|---|---|---|
| SESSION | yes | 缓存作用在session级别,同一个SqlSession中共享 |
| STATEMENT | no | 缓存作用在一个查询级别 |
可以通过在一个sqlSession中反复进行同一个查询的方式验证一级缓存。
测试代码如下:
public class EnvConfigTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void before() {
try (InputStream input = EnvConfigTest.class.getResourceAsStream("/mybatis-config.xml")) {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
sqlSessionFactory = builder.build(input);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Test
public void testSessionCache(){
SqlSession session = this.sqlSessionFactory.openSession();
ApplicationRepository mapper = session.getMapper(ApplicationRepository.class);
AppTestEntity e1 = mapper.queryById(2L);
AppTestEntity e2 = mapper.queryById(2L);
System.out.println("boolean(e1=e2) is "+(e1==e2));
session.close();
}
}设置<setting name="localCacheScope" value="SESSION"/>时的打印结果为:
boolean(e1=e2) is true设置<setting name="localCacheScope" value="STATEMENT"/> 时的打印结果为:
boolean(e1=e2) is false可以看出,STATEMENT作用域的作用范围就是一次sql查询,也就时变相的关闭了Mybatis的一级缓存。而SESSION作用域会在同一个 sqlSession内部共享查询结果。
刷新二级缓存的方法有两种
- 在两次查询之间进行一次增删改操作
- 通过
SqlSession#clearCache方法清空缓存
测试清空缓存
@Test
public void testSessionCache(){
SqlSession session = this.sqlSessionFactory.openSession();
ApplicationRepository mapper = session.getMapper(ApplicationRepository.class);
AppTestEntity e1 = mapper.queryById(2L);
session.clearCache();
AppTestEntity e2 = mapper.queryById(2L);
System.out.println("boolean(e1=e2) is "+(e1==e2));
session.close();
}配置<setting name="localCacheScope" value="SESSION"/>时的打印结果为:
boolean(e1=e2) is false二级缓存
Mybatis的二级缓存可是实现在多个SqlSession中共享,默认是开启的,可以通过 <setting name="cacheEnabled" value="false"/>这个配置项关闭。二级缓存的作用域是一个namespace,即mapper映射文件中的namespace。
可以通过在两个 SqlSession 中查询同一内容的方式验证二级缓存是否生效。测试代码为:
public class EnvConfigTest {
private SqlSessionFactory sqlSessionFactory;
//省略@Before
@Test
public void testCacheFirst() {
SqlSession session1 = this.sqlSessionFactory.openSession();
ApplicationRepository mapper1 = session1.getMapper(ApplicationRepository.class);
SqlSession session2 = this.sqlSessionFactory.openSession();
ApplicationRepository mapper2 = session2.getMapper(ApplicationRepository.class);
System.out.println("==session1查询==");
AppTestEntity e1 = mapper1.queryById(1L);
//提交事务,使二级缓存生效
session1.commit();
System.out.println("==session2查询==");
AppTestEntity e2 = mapper2.queryById(1L);
System.out.println("boolean(session1_e1=session2_e2) is "+(e1==e2));
session1.close();
session2.close();
}
}配置 <setting name="cacheEnabled" value="false"/>时的效果
==session1查询==
==session2查询==
boolean(session1_e1=session2_e2) is false配置 <setting name="cacheEnabled" value="true"/>或不配置时的效果
==session1查询==
==session2查询==
boolean(session1_e1=session2_e2) is true这里需要注意一点,要使二级缓存生效,需要在查询条件后提交事务(或者通过框架控制事务执行,如Spring中的@Transicational注解),如果没有提交事务也不会走二级缓存。如果注释掉测试代码中的 session1.commit();一行,打印结果为:
==session1查询==
==session2查询==
boolean(session1_e1=session2_e2) is falseMybatis一二级缓存的内部实现方式 #坑