在 MyBatis 中,二级缓存是可以共用的。这需要通过节点为命名空间配置参照缓存,比如像下面这样。

1
2
3
4
5
6
7
8
9
10
11
<!-- Mapper1.xml -->
<mapper namespace="xyz.coolblog.dao.Mapper1">
<!-- Mapper1 与 Mapper2 共用一个二级缓存 -->
<cache-ref namespace="xyz.coolblog.dao.Mapper2"/>
</mapper>


<!-- Mapper2.xml -->
<mapper namespace="xyz.coolblog.dao.Mapper2">
<cache/>
</mapper>

配置分析 cache-ref 的解析过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void cacheRefElement(XNode context) {
if (context != null) {
configuration.addCacheRef(builderAssistant.getCurrentNamespace(),
context.getStringAttribute("namespace"));
// 创建 CacheRefResolver 实例
CacheRefResolver cacheRefResolver = new CacheRefResolver(
builderAssistant, context.getStringAttribute("namespace"));
try {
// 解析参照缓存
cacheRefResolver.resolveCacheRef();
} catch (IncompleteElementException e) {
// 捕捉 IncompleteElementException 异常,并将 cacheRefResolver
// 存入到 Configuration 的 incompleteCacheRefs 集合中
configuration.addIncompleteCacheRef(cacheRefResolver);
}
}
}

节点的解析逻辑封装在了 CacheRefResolver 的resolveCacheRef方法中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// -☆- CacheRefResolver
public Cache resolveCacheRef() {
// 调用 builderAssistant 的 useNewCache(namespace) 方法
return assistant.useCacheRef(cacheRefNamespace);
}


// -☆- MapperBuilderAssistant
public Cache useCacheRef(String namespace) {
if (namespace == null) {
throw new BuilderException("……");
}
try {
unresolvedCacheRef = true;
// 根据命名空间从全局配置对象(Configuration)中查找相应的缓存实例
Cache cache = configuration.getCache(namespace);
/*
* 若未查找到缓存实例,此处抛出异常。这里存在两种情况导致未查找到
* cache 实例,分别如下:
* 1.使用者在 <cache-ref> 中配置了一个不存在的命名空间,
* 导致无法找到 cache 实例
* 2.使用者所引用的缓存实例还未创建
*/
if (cache == null) {
throw new IncompleteElementException("……");
}
// 设置 cache 为当前使用缓存
currentCache = cache;
unresolvedCacheRef = false;
return cache;
} catch (IllegalArgumentException e) {
throw new IncompleteElementException("……");
}
}