对select,insert,update,delete的解析是通过buildStatementFromContext来完成的,具体的解析是XMLStatementBuilder来完成的.
支持的属性有
名称 | 说明 |
id | 语句id |
databaseId | 不处理语句情况 1、在配置文件中设置了databaseIdProvider,并且当前设置的databaseId与配置文件中不一致时 2、配置文件 中没有设置,当前设置了databaseId 3、配置文件中没有设置databaseIdProvider,当前没有设置databaseId,有当前id对应的MappedStatement的databaseId不等于null |
flushCache | 布尔值,如果没有设置情况下,如果是select语句,则默认为false,否则为true |
useCache | 布尔值,如果没有设置情况上,select语句默认是true,否则为false |
resultOrdered | 布尔值,没有设置时,默认是false |
parameterType | 设置语句请求参数类型,可以使用别名 |
lang | 设置语言驱动器,默认是XMLLanguageDriver |
selectKey | 生成主键节点 |
useGeneratedKey | 如果没有设置,使用全局配置及当前语句是不是插入语句 。如果为true,则使用Jdbc3KeyGenerator,否则使用NoKeyGenerator |
statementType | 没有设置时默认是PREPARE类型 |
fetchSize | 在StatementHandler中使用,来设置获取大小。 |
timeout | 在StatementHandler中设置语句的执行超时时间 |
parameterMap | 参数映射,已经不推荐使用 |
resultType | 一种特殊的resultMap |
resultMap | 与resultType相当,两者二选一 |
resultSetType | 用于在StatementHandler中设置语句的ResultType的类型 |
keyProperty | 用于设置主属性,有多个属性时,用逗号分隔。用于KeyGenerator |
keyColumn | 用于设置数据库字段主键,有多个时,用逗号分隔。用于KeyGenerator以及用于StatementHandler初始化语句时 |
resultSets | 有多个时,用逗号分隔。用于ResultSetHandler处理 |
selectKey支持的属性
名称 | 说明 |
databaseId | 不处理语句情况 1、在配置文件中设置了databaseIdProvider,并且当前设置的databaseId与配置文件中不一致时 2、配置文件 中没有设置,当前设置了databaseId 3、配置文件中没有设置databaseIdProvider,当前没有设置databaseId,有当前id对应的MappedStatement的databaseId不等于null |
resultType | 返回的数据类型 |
statementType | 如果没有设置,默认是PREPARE类型 |
keyProperty | 主属性 |
keyColumn | 数据库主键 |
order | 在什么时候执行,没有设置时,默认是AFTER |
1、解析语句中的include
XMLIncludeTransformer在解析include节点时,首先找到refid引用的节点,同时解析子节点property的name,value值对。接着在refid的引用的节点上应用applyIncludes递归调用。递归完后,用引用节点替换indlude节点。将引用节点的子结点添加到include之前,然后删除include节点。
在解析非include节点且节点类型是ELEMENT_NODE时,递归遍历子节点
如果解析的是引用节点,且节点是文本结点会作变量替换。
private void applyIncludes(Node source, final Properties variablesContext, boolean included) {
if (source.getNodeName().equals("include")) {
Node toInclude = findSqlFragment(getStringAttribute(source, "refid"), variablesContext);
Properties toIncludeContext = getVariablesContext(source, variablesContext);
applyIncludes(toInclude, toIncludeContext, true);
if (toInclude.getOwnerDocument() != source.getOwnerDocument()) {
toInclude = source.getOwnerDocument().importNode(toInclude, true);
}
source.getParentNode().replaceChild(toInclude, source);
while (toInclude.hasChildNodes()) {
toInclude.getParentNode().insertBefore(toInclude.getFirstChild(), toInclude);
}
toInclude.getParentNode().removeChild(toInclude);
} else if (source.getNodeType() == Node.ELEMENT_NODE) {
NodeList children = source.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
applyIncludes(children.item(i), variablesContext, included);
}
} else if (included && source.getNodeType() == Node.TEXT_NODE
&& !variablesContext.isEmpty()) {
// replace variables ins all text nodes
source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));
}
}
2、解析selectKey节点
此结点在insert节点下,解析后添加到configuration中的keyGenerators中,添加后,删除selectKey节点
private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
List<XNode> selectKeyNodes = context.evalNodes("selectKey");
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) {
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) {
String resultType = nodeToHandle.getStringAttribute("resultType");
Class<?> resultTypeClass = resolveClass(resultType);
StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));
String keyProperty = nodeToHandle.getStringAttribute("keyProperty");
String keyColumn = nodeToHandle.getStringAttribute("keyColumn");
boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER"));
//defaults
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;
SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);
SqlCommandType sqlCommandType = SqlCommandType.SELECT;
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);
MappedStatement keyStatement = configuration.getMappedStatement(id, false);
configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
}
private void removeSelectKeyNodes(List<XNode> selectKeyNodes) {
for (XNode nodeToHandle : selectKeyNodes) {
nodeToHandle.getParent().getNode().removeChild(nodeToHandle.getNode());
}
}
3、根据参数类型创建SqlSource
包含解析动态节点,创建DynamicSqlSource或者RawSqlSource
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
4、创建MappedStatement,添加到Configuration中
//XMLStatementBuilder
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
//MappedBuilderAssistant
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
StatementType statementType,
SqlCommandType sqlCommandType,
Integer fetchSize,
Integer timeout,
String parameterMap,
Class<?> parameterType,
String resultMap,
Class<?> resultType,
ResultSetType resultSetType,
boolean flushCache,
boolean useCache,
boolean resultOrdered,
KeyGenerator keyGenerator,
String keyProperty,
String keyColumn,
String databaseId,
LanguageDriver lang,
String resultSets) {
if (unresolvedCacheRef) {
throw new IncompleteElementException("Cache-ref not yet resolved");
}
id = applyCurrentNamespace(id, false);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
.resource(resource)
.fetchSize(fetchSize)
.timeout(timeout)
.statementType(statementType)
.keyGenerator(keyGenerator)
.keyProperty(keyProperty)
.keyColumn(keyColumn)
.databaseId(databaseId)
.lang(lang)
.resultOrdered(resultOrdered)
.resultSets(resultSets)
.resultMaps(getStatementResultMaps(resultMap, resultType, id))
.resultSetType(resultSetType)
.flushCacheRequired(valueOrDefault(flushCache, !isSelect))
.useCache(valueOrDefault(useCache, isSelect))
.cache(currentCache);
ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
if (statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
}
MappedStatement statement = statementBuilder.build();
configuration.addMappedStatement(statement);
return statement;
}