【Mybatis-源码解析】12 启动过程中,Mapper

1.2 启动过程中,Mapper.xml的解析

整体流程

简易流程图

整体流程解析引用类缓存解析当前类缓存扫描器进行扫描解析入参映射关系解析出参映射关系解析SQL代码块解析SQL执行语句解析SQL节点结束

文本描述

  • 启动时会初始化XMLMapperBuilder对象
    • 内部构建XPathParser
  • 进行解析
    • 解析引用类缓存(cache-ref节点) cacheRefElement
    • 解析当前类缓存(cache节点) cacheElement
      • Configuration在构建过程中会在typeAliasRegistry的TYPE_ALIASES赋值
    • 解析入参映射关系(/mapper/parameterMap 节点)parameterMapElement
    • 解析出参映射关系(/mapper/resultMap 节点)resultMapElements
      • 处理构造函数节点
      • 构建ResultMapping属性
      • 解析discriminator(鉴频器)
    • 解析SQL代码块(/mapper/sql 节点) sqlElement
      • 解析SQL执行语句() buildStatementFromContext 解析
    • 解析SQL节点(select|insert|update|delete节点
      • 解析SelectKeyNodes processSelectKeyNodes

父类接口 BaseBuilder

其他类解析:XPathParser

XML中的使用 XPathParser 进行解析

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typescript复制代码  // 启动时通过此方法构建
public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
configuration,
resource,
sqlFragments);
}

// 核心初始化方法 设置父类的configuration、根据配置和资源构建builder助理、设置parser(解析器)、设置sql片段、设置资源
private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
super(configuration);
this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
this.parser = parser;
this.sqlFragments = sqlFragments;
this.resource = resource;
}

核心方法 parse(解析)

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
scss复制代码  public void parse() {
// 判断资源是否被加载(判断configuration.loadedResources是否有该资源),如果没有加载,进行加载
if (!configuration.isResourceLoaded(resource)) {
// 解析 /mapper 元素 通过xpath解析节点
configurationElement(parser.evalNode("/mapper"));

// 将该资源记载到 configuration.loadedResources中,标记为已加载
configuration.addLoadedResource(resource);

/**
* 根据 Namespace 构建Mapper
* 1. 获取到解析出来的 Namespace 如果 Namespace 不为空 加载该接口
* 2. 判断 configuration.knownMappers 是否有该接口类
* 3. 如果没有在 configuration.loadedResources 中添加 "namespace:" + namespace 类,并将 configuration.knownMappers 添加 该接口类
*/
bindMapperForNamespace();
}

// 获取IncompleteResultMap中在解析过程中失败的ResultMap,再重新进行加载
parsePendingResultMaps();

// 获取IncompleteCacheRef中在解析过程中失败的CacheRef,再重新进行加载
parsePendingCacheRefs();

// 获取IncompleteStatement中在解析过程中失败的Statement,再重新进行加载
parsePendingStatements();
}

解析元素 configurationElement

如果Config中没有解析过该文件

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
csharp复制代码  private void configurationElement(XNode context) {
try {
// 在节点中获取namespace属性 获取到映射的mapper接口类
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}

// 构建器中获取到映射属性
builderAssistant.setCurrentNamespace(namespace);

// 在mapper节点中 获取到cache-ref节点 用于配置引用类缓存
cacheRefElement(context.evalNode("cache-ref"));

// 在mapper节点中 获取cache节点 用于配置当前类缓存
cacheElement(context.evalNode("cache"));

// 在mapper节点中 获取 /mapper/parameterMap 节点 设置参数映射
parameterMapElement(context.evalNodes("/mapper/parameterMap"));

// 在mapper节点中 获取 /mapper/resultMap 节点 设置返回结果
resultMapElements(context.evalNodes("/mapper/resultMap"));

// 在mapper节点中 获取 /mapper/sql 节点
sqlElement(context.evalNodes("/mapper/sql"));

// 解析sql语句
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
}
}

解析引用类缓存(cache-ref节点) cacheRefElement

在当前mapper执行过程中,如果配置了CacheRef,那么CacheRef中配置的接口类,将在当前类使用过程中使用缓存,首先请确保CacheRef中配置的接口类已经使用了缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
java复制代码  private void cacheRefElement(XNode context) {
// 如果节点不为空
if (context != null) {
// 配置中添加缓存信息(添加到cacheRefMap中,KEY为当前的Mapper接口全限定名,value为需要缓存的权限限定名)
configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));

// 构建CacheRefResolver
CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace"));
try {
// 根据缓存的namespace获取缓存对象,并设置当前缓存currentCache
cacheRefResolver.resolveCacheRef();
} catch (IncompleteElementException e) {
// 如果解析失败,存储到IncompleteCacheRef中,在处理完后加载
configuration.addIncompleteCacheRef(cacheRefResolver);
}
}
}

解析当前类缓存(cache节点) cacheElement

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
35
36
37
38
ini复制代码  private void cacheElement(XNode context) throws Exception {
// 如果节点不为空
if (context != null) {
// 在节点中获取type属性,如果type属性为空,那么设置的默认值为:PERPETUAL
String type = context.getStringAttribute("type", "PERPETUAL");

// 根据缓存类型注册缓存获取缓存类
/**
* 在typeAliasRegistry.TYPE_ALIASES中根据类型获取
* 如果获取不到,通过Resources.classForName加载传入的类名
*/
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);

// 在节点中获取eviction属性,如果eviction属性为空,name设置默认值为:LRU
String eviction = context.getStringAttribute("eviction", "LRU");

// 根据eviction类型加载eviction类
Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);

// 在节点中获取flushInterval属性
Long flushInterval = context.getLongAttribute("flushInterval");
// 在节点中获取size属性
Integer size = context.getIntAttribute("size");
// 在节点中获取是否只读标识,默认为false
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
// 在节点中获取是否阻塞标识,默认为false
boolean blocking = context.getBooleanAttribute("blocking", false);
// 在节点中获取子节点 构建成props对象
Properties props = context.getChildrenAsProperties();
// 生成代理器,使用缓存
/**
* 构建缓存对象:设置缓存类、缓存的回收策略、缓存刷新间隔、缓存大小、读写状态、阻塞状态、扩展属性
* 并在configuration中设置缓存对象
* 设置当前类的缓存对象
*/
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
}
}
Configuration在构建过程中会在typeAliasRegistry的TYPE_ALIASES赋值
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
arduino复制代码    typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);

typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);

typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class);
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);

typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);

typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);

typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);

typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
缓存的回收策略
  • LRU:最近最少使用,移除最长时间不被使用的对象
  • FIFO:先进先出,按对象进入缓存的顺序来移除它们
  • SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
  • WEAK:弱引用,更积极地移除基于垃圾收集器和弱引用规则的对象

解析入参映射关系(/mapper/parameterMap 节点)parameterMapElement

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
ini复制代码private void parameterMapElement(List<XNode> list) throws Exception {
// 遍历parameterMap节点
for (XNode parameterMapNode : list) {
// 获取节点中的 ID 属性
String id = parameterMapNode.getStringAttribute("id");

// 获取节点中的 type 属性
String type = parameterMapNode.getStringAttribute("type");

// 加载 type类
Class<?> parameterClass = resolveClass(type);

// 在parameterMap节点中获取到 parameter节点
List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");

// 声明参数参数的映射关系
List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();

// 遍历parameter节点
for (XNode parameterNode : parameterNodes) {
// 在parameter节点中 获取 property、javaType、jdbcType、resultMap、mode、typeHandler、numericScale 属性
/**
* property 类中的属性名
* javaType java类型
* jdbcType 数据库类型
* resultMap 结果映射关系
* mode 标识参数类型:IN - 入参,OUT - 出参,INOUT - 入参和出参
* typeHandler 类型处理器
* numericScale 小数精度
*/
String property = parameterNode.getStringAttribute("property");
String javaType = parameterNode.getStringAttribute("javaType");
String jdbcType = parameterNode.getStringAttribute("jdbcType");
String resultMap = parameterNode.getStringAttribute("resultMap");
String mode = parameterNode.getStringAttribute("mode");
String typeHandler = parameterNode.getStringAttribute("typeHandler");
Integer numericScale = parameterNode.getIntAttribute("numericScale");

// 加载参数类型枚举
ParameterMode modeEnum = resolveParameterMode(mode);

// 加载java类型类
Class<?> javaTypeClass = resolveClass(javaType);
// 获取到jdbc类型枚举
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);

// 加载 类型处理器
Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);

// 根据加载好的参数 构建参数映射
/**
* 1. 解析resultMap (拼接包名)
* 2. 解析javaTypeClass,如果javaType为空那么:判断JdbcType为CURSOR时加载java.sql.ResultSet类,如果返回结果为Map时加载object类,如果获取不到加载Object类型
* 3. 解析类型处理器
* 4. 构建ParameterMapping对象
*/
ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);

// 将结果对象添加到parameterMappings中
parameterMappings.add(parameterMapping);
}

// 构建代理添加 configuration.parameterMaps对象中(KEY 为 id,value为构建好的ParameterMap对象)
builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
}
}

解析出参映射关系(/mapper/resultMap 节点)resultMapElements

遍历所有的resultMap节点 调用resultMapElement方法

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
scss复制代码  private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings) throws Exception {
// 在ThreadLocal中记录
ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());

// 在 节点中获取 id属性
String id = resultMapNode.getStringAttribute("id", resultMapNode.getValueBasedIdentifier());

// 在 节点中获取 type类型,如果type为空获取ofType、如果ofType为空获取resultType、如果resultType为空获取javaType
String type = resultMapNode.getStringAttribute("type",
resultMapNode.getStringAttribute("ofType",
resultMapNode.getStringAttribute("resultType",
resultMapNode.getStringAttribute("javaType"))));

// 在 节点中获取 extend属性
String extend = resultMapNode.getStringAttribute("extends");
// 在 节点中获取 autoMapping属性
Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");

// 加载resultMap的类
Class<?> typeClass = resolveClass(type);

// 声明 discriminator(鉴频器)
Discriminator discriminator = null;
// 声明 resultMappings
List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
// 添加原有的resultMappings
resultMappings.addAll(additionalResultMappings);

// 在resultMap节点中获取子节点
List<XNode> resultChildren = resultMapNode.getChildren();

// 遍历所有的 resultMap节点
for (XNode resultChild : resultChildren) {
// 如果节点名为 构造函数 节点
if ("constructor".equals(resultChild.getName())) {
/**
* 1. 获取constructor节点的子节点
* 2. 添加flags中添加构造函数,如果节点名为idArg那么添加id
* 3. 构建ResultMapping 并将结果添加到resultMappings中
*/
processConstructorElement(resultChild, typeClass, resultMappings);

}
// 如果节点名为 discriminator(鉴频器)
else if ("discriminator".equals(resultChild.getName())) {
// 构建 discriminator(鉴频器)
discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
} else {
// 判断节点名字是否为id 如果为ID 在标志中添加id字段
List<ResultFlag> flags = new ArrayList<ResultFlag>();
if ("id".equals(resultChild.getName())) {
flags.add(ResultFlag.ID);
}
// 构建ResultMapping 并将结果添加到resultMappings中
resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
}
}

// 根据上述属性构建 resultMapResolver
ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
try {
/**
* 1. 如果当前resultMap设置了集成属性,在configuration中获取继承的ResultMap,并取 继承的和本身的并集
* 2. 将组装好的ResultMap存储在configuration的resultMaps中 key 为 设置的ID value 为构建好的映射关系合集
*/
return resultMapResolver.resolve();
} catch (IncompleteElementException e) {
// 如果解析异常了,存放到IncompleteResultMap中,在处理结束后再次加载
configuration.addIncompleteResultMap(resultMapResolver);
throw e;
}
}
处理构造函数节点
1
2
3
4
5
6
7
8
9
10
11
csharp复制代码  private void processConstructorElement(XNode resultChild, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
List<XNode> argChildren = resultChild.getChildren();
for (XNode argChild : argChildren) {
List<ResultFlag> flags = new ArrayList<ResultFlag>();
flags.add(ResultFlag.CONSTRUCTOR);
if ("idArg".equals(argChild.getName())) {
flags.add(ResultFlag.ID);
}
resultMappings.add(buildResultMappingFromContext(argChild, resultType, flags));
}
}
构建ResultMapping属性
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
ini复制代码  private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags) throws Exception {
String property;
// 如果存在构造函数标志 property为节点中的name属性 否则 为节点的property属性
if (flags.contains(ResultFlag.CONSTRUCTOR)) {
property = context.getStringAttribute("name");
} else {
property = context.getStringAttribute("property");
}

// 在节点中获取 column 列名
String column = context.getStringAttribute("column");
// 在节点中获取 javaType java类型
String javaType = context.getStringAttribute("javaType");
// 在节点中获取 jdbcType 数据库类型
String jdbcType = context.getStringAttribute("jdbcType");

// 在节点中获取 select 用于执行对应的select语句
String nestedSelect = context.getStringAttribute("select");

// 在节点中获取 resultMap
String nestedResultMap = context.getStringAttribute("resultMap",
processNestedResultMappings(context, Collections.<ResultMapping> emptyList()));

// 在节点中获取 notNullColumn 不为空的列 (如果该列为空,不生成子对象 - 待认证
String notNullColumn = context.getStringAttribute("notNullColumn");

// 在节点中获取 columnPrefix 当有多个结果集时,用该字段区分
String columnPrefix = context.getStringAttribute("columnPrefix");

// 在节点中获取 typeHandler 类型处理器
String typeHandler = context.getStringAttribute("typeHandler");

// 在节点中获取 resultSet 当有多个结果集时 获取设置的结果集
String resultSet = context.getStringAttribute("resultSet");
// 在节点中获取 foreignColumn 当有多个结果集时 映射字段
String foreignColumn = context.getStringAttribute("foreignColumn");

// 在节点中获取 fetchType 默认值为 在配置中获取的是否启动懒加载,如果启动返回TRUE 否则返回 FALSE
boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));

// 加载 java类
Class<?> javaTypeClass = resolveClass(javaType);

// 加载 类型处理器类
Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);

// 解析 jdbc类型
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);

// 构建代理 根据配置 构建ResultMapping对象返回
return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet, foreignColumn, lazy);
}
解析discriminator(鉴频器)
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
ini复制代码  private Discriminator processDiscriminatorElement(XNode context, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
// 在节点中获取到 column 列名
String column = context.getStringAttribute("column");
// 在节点中获取到 javaType java类型
String javaType = context.getStringAttribute("javaType");
// 在节点中获取到 jdbcType 数据库类型
String jdbcType = context.getStringAttribute("jdbcType");
// 在节点中获取到 typeHandler 类型处理器
String typeHandler = context.getStringAttribute("typeHandler");

// 解析java类
Class<?> javaTypeClass = resolveClass(javaType);
// 解析类型处理器
Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
// 解析数据库类型
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);

// 声明discriminator(鉴频器)Map
Map<String, String> discriminatorMap = new HashMap<String, String>();
// 遍历所有的子节点
for (XNode caseChild : context.getChildren()) {
// 获取子节点的 value 属性
String value = caseChild.getStringAttribute("value");
// 获取子节点的 resultMap 属性
String resultMap = ceChild.getStringAttribute("resultMap", processNestedResultMappings(caseChild, resultMappings));
// 将value 和 resultMap 放置到discriminatorMap中
discriminatorMap.put(value, resultMap);
}
// 构建 discriminator(鉴频器)
return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap);
}

解析SQL代码块(/mapper/sql 节点) sqlElement

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java复制代码  private void sqlElement(List<XNode> list) throws Exception {
// 如果 数据库配置了 DatabaseId(数据库厂商 方言)使用方言解析sql 额否则直接解析
if (configuration.getDatabaseId() != null) {
sqlElement(list, configuration.getDatabaseId());
}
sqlElement(list, null);
}

private void sqlElement(List<XNode> list, String requiredDatabaseId) throws Exception {
// 遍历所有的sql节点
for (XNode context : list) {
// 在节点中获取 databaseId 数据库方言
String databaseId = context.getStringAttribute("databaseId");
// 在节点中获取 id 属性
String id = context.getStringAttribute("id");
// 组装当前的命名空间 将 id 和当前类锁定
id = builderAssistant.applyCurrentNamespace(id, false);
// 判断 databaseId (数据库方言) 是否匹配 如果匹配在sqlFragments添加记录 (同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃)
if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
sqlFragments.put(id, context);
}
}
}
解析SQL执行语句() buildStatementFromContext 解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
scss复制代码  private void buildStatementFromContext(List<XNode> list) {
// 如果 数据库配置了 DatabaseId(数据库厂商 方言)使用方言解析sql 额否则直接解析
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
buildStatementFromContext(list, null);
}

// 解析 SQL 语句
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
// 遍历所有节点
for (XNode context : list) {
// 创建一个xml构建器
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
// 使用构建器解析
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
// 如果解析失败,添加到IncompleteStatement中,等当前文件解析完后重新构建
configuration.addIncompleteStatement(statementParser);
}
}
}

解析SQL节点(select|insert|update|delete节点)XMLStatementBuilder.parseStatementNode

使用XMLStatementBuilder解析

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
ini复制代码  public void parseStatementNode() {
// sql节点中 获取 id
String id = context.getStringAttribute("id");
// sql节点中 获取 数据库方言
String databaseId = context.getStringAttribute("databaseId");

// 如果数据库方言不匹配直接返回
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}

// sql节点中 获取 fetchSize
Integer fetchSize = context.getIntAttribute("fetchSize");
// sql节点中 获取 timeout 超时时间
Integer timeout = context.getIntAttribute("timeout");
// sql节点中 获取 parameterMap 参数映射
String parameterMap = context.getStringAttribute("parameterMap");
// sql节点中 获取 parameterType 参数类型
String parameterType = context.getStringAttribute("parameterType");

// 解析参数类型
Class<?> parameterTypeClass = resolveClass(parameterType);

// sql节点中 获取 resultMap 结果映射
String resultMap = context.getStringAttribute("resultMap");
// sql节点中 获取 resultType 结果类型
String resultType = context.getStringAttribute("resultType");

// sql节点中 获取 lang 为特定的语句指定语言(驱动类)?
String lang = context.getStringAttribute("lang");
// 解析语言驱动
LanguageDriver langDriver = getLanguageDriver(lang);

// 解析结果类型
Class<?> resultTypeClass = resolveClass(resultType);

// sql节点中 获取 resultSetType 指定的结果类型
String resultSetType = context.getStringAttribute("resultSetType");

// sql节点中 获取并解析 statementType 语句类型
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
// 解析 结果类型
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);

// 获取节点的名字
String nodeName = context.getNode().getNodeName();
// 获取节点的SQL语句类型
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));

// 如果为查询语句,那么设置标记
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;

// sql节点中 获取 flushCache 是否刷新缓存,默认不是查询都会开启
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);

// sql节点中 获取 useCache 是否使用缓存,默认是查询都会开启
boolean useCache = context.getBooleanAttribute("useCache", isSelect);


// sql节点中 获取 resultOrdered 是否返回多个结果集,默认是不开启
boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);

// 解析 include 节点
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());

// 解析 SelectKey 节点
processSelectKeyNodes(id, parameterTypeClass, langDriver);

// Parse the SQL (pre: <selectKey> and <include> were parsed and removed)

// langDriver(语言驱动)创建SQL原数据 (设置不同节点的节点处理器)
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);


// sql节点中 获取 resultSets 返回结果的集合名字
String resultSets = context.getStringAttribute("resultSets");
// sql节点中 获取 keyProperty 返回后设置的属性名
String keyProperty = context.getStringAttribute("keyProperty");
// sql节点中 获取 keyColumn 返回后设置的属性的列
String keyColumn = context.getStringAttribute("keyColumn");

// 声明Key生成器
KeyGenerator keyGenerator;
// 声明 keyStatementId ? 为当前SQL语句的ID + !selectKey
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
// 构建当前类的ID
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);

// 如果配置有ID生成器 通过ID生成器获取keyGenerator 否则 在节点中获取 useGeneratedKeys 使用的KEY生成器
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}

// 构建MappedStatement 构建 MappedStatement 存放在 Configuration.ji sql查询的id
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
解析SelectKeyNodes processSelectKeyNodes
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
ini复制代码  private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
// sql节点中 获取 selectKey 节点
List<XNode> selectKeyNodes = context.evalNodes("selectKey");

// 如果 数据库配置了 DatabaseId(数据库厂商 方言)使用方言解析 额否则直接解析
if (configuration.getDatabaseId() != null) {
parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
}
parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);


removeSelectKeyNodes(selectKeyNodes);
}

private void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) {
// 遍历获取到的节点
for (XNode nodeToHandle : list) {
// 设置id (由SQL语句的ID + !selectKey 组成)
String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;

// 获取数据库驱动
String databaseId = nodeToHandle.getStringAttribute("databaseId");

// 如果驱动一致
if (databaseIdMatchesCurrent(id, databaseId, skRequiredDatabaseId)) {
parseSelectKeyNode(id, nodeToHandle, parameterTypeClass, langDriver, databaseId);
}
}
}

private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) {
// 在节点中 获取 resultType 结果类型
String resultType = nodeToHandle.getStringAttribute("resultType");
// 解析结果类型
Class<?> resultTypeClass = resolveClass(resultType);

// sql节点中 获取并解析 statementType 语句类型
StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));

// sql节点中 获取 keyProperty 语句结果应该被设置到的目标属性。如果生成列不止一个,可以用逗号分隔多个属性名称
String keyProperty = nodeToHandle.getStringAttribute("keyProperty");

// 在节点中 获取 keyColumn 返回结果集中生成列属性的列名。如果生成列不止一个,可以用逗号分隔多个属性名称
String keyColumn = nodeToHandle.getStringAttribute("keyColumn");

// 在节点中 获取 order 设置selectKey的执行属性 在执行语句之前,还是之后
boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER"));

// 设置默认值 不适用缓存、没有多个结果集、没有Key生成器、返回大小为空、不设置超时时间、不刷新缓存、入参映射为空、出参映射为空、返回结果为空
boolean useCache = false;
boolean resultOrdered = false;
KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
Integer fetchSize = null;
Integer timeout = null;
boolean flushCache = false;
String parameterMap = null;
String resultMap = null;
ResultSetType resultSetTypeEnum = null;

// langDriver(语言驱动)创建SQL原数据 (设置不同节点的节点处理器)
SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);

// SQL执行类型为SELECT(查询)
SqlCommandType sqlCommandType = SqlCommandType.SELECT;

// 构建MappedStatement 构建 MappedStatement 存放在 Configuration.mappedStatements KEY为SelectKey的id
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, null);

id = builderAssistant.applyCurrentNamespace(id, false);

// 并将当前SQL存在 configuration.keyGenerators 中 key为SQL语句的ID
MappedStatement keyStatement = configuration.getMappedStatement(id, false);
configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
}

文章链接

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%