2.4Mybatis——缓存机制-一二级缓存

时间:2024-10-07 06:56:36

使用第二种方法正常执行,但使用第一种方法时,提示序列化异常:Cause: java.io.NotSerializableException: org.wyy.dto.Address
这又是什么原因呢?

一级缓存

根据前面几篇文章的描述,我们知道mapper方法的执行分为SQL的映射和SQL的执行,执行阶段又分为执行器构建、statement构建、参数处理、SQL语句执行、结果集处理这几个阶段。
以查询为例,猜想缓存应该是在执行阶段的结果集处理之后,将查询和结果缓存起来。看一下源码:

@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
  BoundSql boundSql = ms.getBoundSql(parameterObject);
  // 构建缓存键
  CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
  return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

public <E> List<E> query(...){
	// 从本地缓存中获取, localCache是PerpetualCache类型
	list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
}

public class PerpetualCache implements Cache {
	private final String id;
	private Map<Object, Object> cache = new HashMap<>();
}

一级缓存本质是使用Map进行保存,不涉及序列化操作,所以测试中正常执行。

二级缓存

Mybatis默认使用SerializedCache作为二级缓存,由于二级缓存存在持久化和跨会话共享等场景的要求,为了保证缓存对象的完整,被缓存的对象必须实现序列化接口。
除了使用Mybatis默认的二级缓存实现,如果想要自定义二级缓存,只需要实现Mybatis的Cache接口即可,比如通过集成Ehcache或redis来作为Mybatis的缓存实现。

<dependency>
   <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.2</version>
</dependency>
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-redis</artifactId>
    <version>1.0.0-beta2</version>
</dependency>

对于二级缓存而言,官方文档还提供了缓存的容量、驱逐策略等配置属性,感兴趣可以继续探究。