1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 开启mybatis日志_Mybatis源码分析之Cache二级缓存原理 (五)

开启mybatis日志_Mybatis源码分析之Cache二级缓存原理 (五)

时间:2023-06-04 03:20:02

相关推荐

开启mybatis日志_Mybatis源码分析之Cache二级缓存原理 (五)

一:Cache类的介绍

讲解缓存之前我们需要先了解一下Cache接口以及实现MyBatis定义了一个org.apache.ibatis.cache.Cache接口作为其Cache提供者的SPI(ServiceProvider Interface) ,所有的MyBatis内部的Cache缓存,都应该实现这一接口

Cache的实现类中,Cache有不同的功能,每个功能独立,互不影响,则对于不同的Cache功能,这里使用了装饰者模式实现。

看下cache的实现类,如下图:

1.FIFOCache:先进先出算法 回收策略,装饰类,内部维护了一个队列,来保证FIFO,一旦超出指定的大小,

则从队列中获取Key并从被包装的Cache中移除该键值对。

2.LoggingCache:输出缓存命中的日志信息,如果开启了DEBUG模式,则会输出命中率日志。

3.LruCache:最近最少使用算法,缓存回收策略,在内部保存一个LinkedHashMap

4.ScheduledCache:定时清空Cache,但是并没有开始一个定时任务,而是在使用Cache的时候,才去检查时间是否到了。

5.SerializedCache:序列化功能,将值序列化后存到缓存中。该功能用于缓存返回一份实例的Copy,用于保存线程安全。

6.SoftCache:基于软引用实现的缓存管理策略,软引用回收策略,软引用只有当内存不足时才会被垃圾收集器回收

7.SynchronizedCache:同步的缓存装饰器,用于防止多线程并发访问

8.PerpetualCache 永久缓存,一旦存入就一直保持,内部就是一个HashMap

9.WeakCache:基于弱引用实现的缓存管理策略

10.TransactionalCache 事务缓存,一次性存入多个缓存,移除多个缓存

11.BlockingCache 可阻塞的缓存,内部实现是ConcurrentHashMap

二:二级缓存初始化

Mybatis默认对二级缓存是关闭的,一级缓存默认开启,如果需要开启只需在mapper上加入

二级缓存是怎么初始化的呢?

我们在之前的文章里面(Mybatis源码分析之SqlSessionFactory(一))分析了配置文件的加载,我们回到那边来找到二级缓存的加载地方,一开始我就说了“如果需要开启只需在mapper上加入

XMLConfigBuilder.parse-->parseConfiguration(XNode root)-->mapperElement(root.evalNode("mappers"))-->

mapperElement(XNode parent)

看下mapperElement的方法

private void mapperElement(XNode parent) throws Exception {

if (parent != ) {

for (XNode child : parent.getChildren) {

if ("package".equals(child.getName)) {

String mapperPackage = child.getStringAttribute("name");

configuration.addMappers(mapperPackage);

} else {

String resource = child.getStringAttribute("resource");

String url = child.getStringAttribute("url");

String mapperClass = child.getStringAttribute("class");

if (resource != && url == && mapperClass == ) {

ErrorContext.instance.resource(resource);

InputStream inputStream = Resources.getResourceAsStream(resource);

XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments);

mapperParser.parse;

} else if (resource == && url != && mapperClass == ) {

ErrorContext.instance.resource(url);

InputStream inputStream = Resources.getUrlAsStream(url);

XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments);

mapperParser.parse;

} else if (resource == && url == && mapperClass != ) {

Class mapperInterface = Resources.classForName(mapperClass);

configuration.addMapper(mapperInterface);

} else {

throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");

}

}

}

}

}

这个时候我已经找到了mapper节点了,我们在看向前走

XMLMapperBuilder.mapperParser.parse

代码如下

public void parse {

if (!configuration.isResourceLoaded(resource)) {

configurationElement(parser.evalNode("/mapper"));

configuration.addLoadedResource(resource);

bindMapperForNamespace;

}

parsePendingResultMaps;

parsePendingChacheRefs;

parsePendingStatements;

}

看到configurationElement(parser.evalNode("/mapper"));看到mapper节点了继续走

private void configurationElement(XNode context) {

try {

String namespace = context.getStringAttribute("namespace");

if (namespace == || namespace.equals("")) {

throw new BuilderException("Mapper's namespace cannot be empty");

}

builderAssistant.setCurrentNamespace(namespace);

cacheRefElement(context.evalNode("cache-ref"));

cacheElement(context.evalNode("cache"));

parameterMapElement(context.evalNodes("/mapper/parameterMap"));

resultMapElements(context.evalNodes("/mapper/resultMap"));

sqlElement(context.evalNodes("/mapper/sql"));

buildStatementFromContext(context.evalNodes("select|insert|update|delete"));

} catch (Exception e) {

throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);

}

}

到这里终于见到了他cacheElement(context.evalNode("cache"));

看源码

private void cacheElement(XNode context) throws Exception {

if (context != ) {

String type = context.getStringAttribute("type

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。