嘘~ 正在从服务器偷取页面 . . .

Mybatis(七)Mybatis缓存


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 二级缓存

二级缓存命中的原则

二级缓存的生命周期



文章作者: Small-Rose /张小菜
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-SA 4.0 许可协议。转载请注明来源 Small-Rose /张小菜 !
评论
  目录