Mybatis sql 语句简单分析
今天这篇 Mapper 语句解析文章说实话,没有什么技术含量,就是简单说明一下都做了些什么,没有对具体的内容进行分析,详细分析放在后边。
Mapper 语句的解析主要是在 XMLStatementBuilder#parseStatementNode 方法上
首先查看一下代码:
public void parseStatementNode() {
// sql 节点
String id = context.getStringAttribute("id");
String databaseId = context.getStringAttribute("databaseId");
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) { // <1>
return;
}
String nodeName = context.getNode().getNodeName();
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
boolean useCache = context.getBooleanAttribute("useCache", isSelect);
boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
// Include Fragments before parsing
/*
<select id="findById">
select <include refid = "baseSql"/>
from table
</select>
替换成
<select id="findById">
select id, name
from table
</select>
*/
// <2> 替换 sql 中的 include 节点为真正的 sql 内容
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
// 获取 parameterType Class,可能是 null
String parameterType = context.getStringAttribute("parameterType");
Class<?> parameterTypeClass = resolveClass(parameterType);
// TODO 目前不知道干什么的
// select|insert|update|delete|sql 语句才有 lang 属性
String lang = context.getStringAttribute("lang");
LanguageDriver langDriver = getLanguageDriver(lang);
// Parse selectKey after includes and remove them.
// 处理 selectKey 节点 只有 insert 和 update 才有该节点
// <3>
processSelectKeyNodes(id, parameterTypeClass, langDriver);
// Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
KeyGenerator keyGenerator;
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
// 同意成为 全限定类目.id
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
// 判断是否存在 keyGenerator
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
// 如果设置了 useGeneratedKeys 属性,属性值也是 true,则 keyGenerator = Jdbc3KeyGenerator.INSTANCE
// 否则 keyGenerator = NoKeyGenerator.INSTANCE;
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}
// <4> 创建当前 sql 的 sqlSource
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
String resultType = context.getStringAttribute("resultType");
Class<?> resultTypeClass = resolveClass(resultType);
String resultMap = context.getStringAttribute("resultMap");
String resultSetType = context.getStringAttribute("resultSetType");
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
if (resultSetTypeEnum == null) {
resultSetTypeEnum = configuration.getDefaultResultSetType();
}
String keyProperty = context.getStringAttribute("keyProperty");
String keyColumn = context.getStringAttribute("keyColumn");
String resultSets = context.getStringAttribute("resultSets");
// <5> 创建 MappedStatement 并且保存在 Configuration#mappedStatements 中
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
-
因为 Mybatis 是支持多数据源和不同数据厂商的,在代码 <1> 处 this.requiredDatabaseId 在有值的情况下是 Configuration#databaseId 的值,如果与 sql 中的 databaseId 不匹配的话就不进行 sql 解析了。
-
在代码 <2> 处 是 对 标签进行替换,见
[juejin.cn/post/708080…] MybatisSql语句解析之Include节点的替换
-
在代码 <3> 处,是对 节点中的 节点进行解析,后续会进行分析
-
在代码<4>处,是对当前 sql ,用于后续对该 sql 的执行
-
在代码<5>处,就是根据以上的参数创建一个 MappedStatement 并添加到 Configuration#mappedStatements中。