最近在解决性能问题的时候,在与spring btach中的某个tasklet分页查询数据并进行数据的处理的时候,大概压了40w的数据,当然在结果集中解析出来的数据对象更大,结果导致了OOM问题,用内存分析工具MemoryAnalyzer查看到了大对象的内存占用指向了mybatis查询出来的对象,然后就去跟踪调用,结果跟踪到了mybatis的CacheExecutor,于是想到可能是mybatis的缓存,但是之前没有对它进行详细的了解,所以就掉坑里了,没有仔细的思考,很轻易的跳过了这种可能性.
Mybatis的缓存按照作用域划分可以分为,
一级缓存: **sqlsession** 级别的缓存
二级缓存: **namespace**级别的缓存
使用mybatis-spring时: 每次查询spring会重新创建sqlsession,所以一级缓存是不生效的.
但是当开启事务时,spring会使用同一个sqlsession查询,这种情况下一级缓存时生效的.
在一级缓存中,当sqlSession执行写入更新,删除,则会清除sqlSession中的一级缓存.
public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List list = (List) tcm.getObject(cache, key);
if (list == null) {
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
二级缓存开启后,同一个namespace下的所有操作语句,都影响这同一个cache,即二级缓存被多个sqlsession共享,是一个全局的变量.