Mybatis缓存
使用缓存减少数据库操作。
Mybatis缓存分以及缓存和二级缓存。
一级缓存指的是SqlSession,是会话级的缓存。
Mybatis一级缓存
一级缓存命中的原则
缓存命中,其实就是判断两次查询如何判断是一样的。
(1)statementId 必须相同
<select id="selectByMap" parameterType="map" resultMap="empMap">
select id, name,email from emplee
where name like concat('%',#{name},'%')
</select>
statementId 就是这个查询语句的Id,”selectByMap”。
Mybatis要命中缓存,要求两次查询的statementId必须一致,否则无法命中缓存,即使查询语句、参数完全一致也不能命中。
(2)查询参数
Mybatis要命中缓存,要求查询参数完全一样,否则无法命中缓存。
这里的查询参数相同,指的是实际传递给SQL使用的参数一样。
(3)分页参数
Mybatis要命中缓存,要求分页参数完全一样,否则无法命中缓存。
RowBounds rb1 = new RowBounds(0, 10);
List<Employee> list1 = sqlSession.selectList("com.xiaocai.mybatis.dao.EmpDao.list", null, rb1);
RowBounds rb2 = new RowBounds(0, 11);
List<Employee> list2 = sqlSession.selectList("com.xiaocai.mybatis.dao.EmpDao.list", null, rb2);
list1 == list2
两次查询无法命中。
(4)SQL语句
Mybatis要命中缓存,要求两次执行的SQL文本语句一样,即使是相同语义的SQL也无法命中。
(5)环境
这里的环境是指 <environment>
标签配置的环境。
一级缓存的生命周期
Mybatis 缓存什么时候产生的?什么时候销毁的?
Mybatis产生缓存实际上是调用sqlsession中select开头的系列方法,如select、 selectOne、 SelectList 、selectMap
Mybatis 缓存清空的几种情况
(1)会在session关闭的时候清空缓存。
List<Employee> list1 = sqlSession.selectList("com.xiaocai.mybatis.dao.EmpDao.list", null, rb1);
Field executorField = sqlSession.getClass().getDeclaredField("executor");
executorField.setAccessible(true);
CacheingExecutor cacheingExecutor = (CacheingExecutor)executorField.get(sqlSession);
Field declaredField = cacheingExecutor.getDeclaredField("deledate");
declaredField.setAccessible(true);
SimpleExecutor simpleExecutor = (SimpleExecutor)declaredField.get(cacheingExecutor);
Field localCacheField = simpleExecutor.getClass().getSupperclass().getDeclaredField("localCache");
localCacheField.setAccessible(true);
PerpetualCache perpetualCache = (PerpetualCache)declaredField.get(simpleExecutor);
Field cacheField = perpetualCache.getClass().getDeclaredField("cache");
cacheField.setAccessible(true);
Map<Object, Object> map = (Map<Object, Object>)cacheField.get(perpetualCache);
for(map.Entry<Object, Object> entry: map.entrySet()){
logger.info(entry.getKey() +" --- " + entry.getValue());
}
sqlSession.close();
for(map.Entry<Object, Object> entry: map.entrySet()){
logger.info(entry.getKey() +" --- " + entry.getValue());
}
(2)执行 commit 操作会清空缓存
List<Employee> list1 = sqlSession.selectList("com.xiaocai.mybatis.dao.EmpDao.list", "张");
sqlSession.commit();
List<Employee> list2 = sqlSession.selectList("com.xiaocai.mybatis.dao.EmpDao.list", "张");
第二次会查询数据库。
(3)执行 rollback 操作会清空缓存
List<Employee> list1 = sqlSession.selectList("com.xiaocai.mybatis.dao.EmpDao.list", "张");
sqlSession.rollback();
List<Employee> list2 = sqlSession.selectList("com.xiaocai.mybatis.dao.EmpDao.list", "张");
第二次会查询数据库。
(4)执行 update/insert/delete 操作会清空缓存
List<Employee> list1 = sqlSession.selectList("com.xiaocai.mybatis.dao.EmpDao.list", "张");
sqlSession.update("com.xiaocai.mybatis.dao.EmpDao.update", 1);
List<Employee> list2 = sqlSession.selectList("com.xiaocai.mybatis.dao.EmpDao.list", "张");
第二次查询会查询数据库。
这里如果更新的如果不是查询的表,同样会清空缓存,一样会清空所有的缓存。
(5)执行 clearCache 主动清空缓存
sqlSession.clearCache();
Mybatis 一级缓存脏读问题。
Mybatis 不存在以及缓存脏读问题。关闭Session ,执行Commit,执行Rollback 都会清空Mybatis一级缓存,实际上Mybatis的一级缓存的生命周期是在数据库事务的声明周期之内。Mybatis的一级缓存提高数据库事务的隔离级别。
Mybatis 二级缓存
二级缓存命中的原则
二级缓存的生命周期