MyBatis缓存
MyBatis 有 一级缓存 和 二级缓存。
一级缓存
一级缓存,默认就是开启的,范围是 Session。
可通过 localCacheScope 设置不同的范围,支持两种范围:
-
SESSION:同一个 SQL Session 内的查询共享数据。(默认配置)
(类似事务隔离级别中的 “Repeatable Read”) -
STATEMENT:缓存仅用于语句执行;同一个 SQL Session 内的不同调用不会共享数据。
(类似 “Read Committed”)
注意:MyBatis中的Session与Spring中的事务绑定。
Spring默认每次都创建一个新的SqlSession,所以一级缓存无效。
如果在同一个事务中执行sql,则使用同一个SqlSession,一级缓存生效。
可将日志级别设置为 Debug,查看 SqlSession 信息。
二级缓存(Mapper)
二级缓存 是 Mapper 级别的缓存,默认是关闭的。
可通过在Mapper文件中添加 <cache/> 开启。最好有完善的测试数据支撑开启二级缓存的决定(包括调整参数)。
- Mapper 文件中,所有 Select 语句会被缓存
- Mapper 文件中,所有 Insert、Update、Delete 语句会刷新缓存
- 默认使用 LRU(Least Recently Used)算法回收缓存空间
这是最通用的算法。FIFO(先将先出)和 基于GC的SOFT(软引用)、WEAK(弱引用)的适用场景较少。 - 默认没有定时刷新,只在执行语句时刷新
- 默认缓存1024个列表或对象(引用)
- 默认缓存既可读又可写
只读的缓存性能更好,但可写的模式更安全。
自定义缓存实现
通过实现 org.apache.ibatis.cache.Cache 接口,并在 <cache/> 中指定类型就能使用自定义的缓存。
<cache type="com.domain.something.MyCustomCache"/>
public interface Cache { String getId(); void putObject(); Object getObject(); Object removeObject(); void clear(); int getSize(); ReadWriteLock getReadWriteLock(); }
不用缓存
禁用二级缓存
1. 对于二级缓存,如果不想用,可以不配置,因为默认就是关闭的。
2. 如果只想在部分语句中禁用,则可以将 useCache 设置为 false,防止执行结果被存入二级缓存。
另,如果 flushCache = true,则句执行后,对应的 一级缓存 和 二级缓存 都会被刷新。
不同SQL的默认 flushCache 和 useCache 设置:
<select ... flushCache="false" useCache="true" /> <insert ... flushCache="true" /> <update ... flushCache="true" /> <delete ... flushCache="true" />
禁用一级缓存
1. 上述将 flushCache 设置为false 的方法也可以达到禁用一级缓存的效果。
2. 将一级缓存的范围改为 Statement 也可以满足部分场景需求。
3. 也可以在更上层的业务代码中避开缓存。MyBatis的Session是与Spring中的事务绑定的。如果将事务传播行为设置为 REQUIRES_NEW,则相关业务方法就进入了新的Session,不会去使用原Session中的缓存数据。
@Transactional(propagation=Propagation.REQUIRES_NEW)