Mybatis 查询结果 List 使用 remove 方法后再次查询,结果与数据库不一致,原因是 Mybatis 缓存机制
1 问题场景使用 Mybatis 查询,结果为对象的 List ,使用 remove 方法删除结果List中的一个对象之后,使用相同参数再次查询,发现查询结果与数据库不一致,而是第一次查询结果 remove 操作后的对象列表。2 原因分析根据问题现象可以发现,相同查询条件下,第二次查询使用了第一次的查询结果,而且两次查询是在不同的方法中进行,第一次的对象肯定会被GC回收,所以应该有某种缓存机制存在
1 问题场景
使用 Mybatis 查询,结果为对象的 List ,使用 remove 方法删除结果List中的一个对象之后,使用相同参数再次查询,发现查询结果与数据库不一致,而是第一次查询结果 remove 操作后的对象列表。
2 问题解决
根据问题现象可以发现,相同查询条件下,第二次查询使用了第一次的查询结果,而且两次查询是在不同的方法中进行,第一次的对象肯定会被GC回收,所以应该有某种缓存机制存在,那么只可能是 Mybatis 实现了某种缓存机制。
经过查询 Mybatis 缓存机制原理,调整一级缓存(也称本地缓存)为 STATEMENT 级别,多次查询结果均与数据库一致。
将一级缓存级别调整为STATEMENT 示例代码:
SqlSessionFactoryBean bean = new SqlSessionFactoryBean ();
bean.setDataSource (dataSource);
// 调整一级缓存级别为 STATEMENT
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLocalCacheScope(LocalCacheScope.STATEMENT);
bean.setConfiguration(configuration);
3 问题总结
使用 Mybatis 时,要结合具体场景注意缓存使用问题。
4 Mybatis 缓存机制简介
MyBatis 有一级缓存和二级缓存,并且预留了集成第三方缓存的接口。
4.1 一级缓存
定义:一级缓存也叫本地缓存,MyBatis 的一级缓存是在会话(SqlSession)层面进行缓存的。MyBatis 的一级缓存是默认开启的,不需要任何的配置。
一级缓存的缺点:使用一级缓存的时候,由于缓存不能跨会话共享,不同的会话之间对于相同的数据可能有不一样的缓存。在有多个会话、或者分布式环境、或者本地对查询结果进行了增删改(本问题的场景)的情况下,会出现脏数据的问题。
一级缓存级别调整:MyBatis 一级缓存(MyBaits 称其为 Local Cache)无法关闭,但是有两种级别可选,如下所示:
缓存级别 | 处理方式 |
---|---|
session 级别的缓存(默认) | 在同一个 sqlSession 内,对同样的查询将不再查询数据库,直接从缓存中获取 |
statement 级别的缓存 | 每次查询结束都会清掉一级缓存;将一级缓存的级别设为 statement 级别可避免脏数据问题 |
4.2 二级缓存
二级缓存是用来解决一级缓存不能跨会话共享的问题的,范围是namespace 级别的,可以被多个SqlSession 共享(只要是同一个接口里面的相同方法,都可以共享),生命周期和应用同步。
如果 MyBatis 使用了二级缓存,并且你 Mapper 和 select 语句也配置使用了二级缓存,那么在执行select查询的时候,MyBatis会先从二级缓存中取输入,其次才是一级缓存,即MyBatis查询数据的顺序是:二级缓存 —> 一级缓存 —> 数据库。
参考资料:mybatis缓存机制 - 吴振照 - 博客园,关于 Mybatis 缓存机制的详细讲解。
更多推荐
所有评论(0)