源码剖析-初始化-如何解析的映射配置文件?
# 前言
# select
select 元素允许你配置很多属性来配置每条语句的行为细节
<select
id="select"
parameterType="int"
parameterMap="deprecated"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY">
# insert, update 和 delete
数据变更语句 insert,update 和 delete 的实现非常接近
<insert
id="insert"
parameterType="com.itheima.pojo.User"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20">
<update
id="update"
parameterType="com.itheima.pojo.User"
flushCache="true"
statementType="PREPARED"
timeout="20">
<delete
id="delete"
parameterType="com.itheima.pojo.User"
flushCache="true"
statementType="PREPARED"
timeout="20">
# 动态sql
借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类
- if
- choose (when, otherwise) MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
问题:映射配置文件中标签和属性如何被解析封装的?
问题:sql占位符如何进行的替换?动态sql如何进行的解析?
# 解析映射配置文件源码流程:
# 入口:XMLConfigBuilder#mapperElement
解析全局配置文件中的标签
/**
* 解析<mappers>标签
* @param parent mappers标签对应的XNode对象
* @throws Exception
*/
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
// 获取<mappers>标签的子标签
for (XNode child : parent.getChildren()) {
// <package>子标签
if ("package".equals(child.getName())) {
// 获取mapper接口和mapper映射文件对应的package包名
String mapperPackage = child.getStringAttribute("name");
// 将包下所有的mapper接口以及它的代理对象存储到一个Map集合中,key为mapper接口类型,value为代理对象工厂
configuration.addMappers(mapperPackage);
} else {// <mapper>子标签
// 获取<mapper>子标签的resource属性
String resource = child.getStringAttribute("resource");
// 获取<mapper>子标签的url属性
String url = child.getStringAttribute("url");
// 获取<mapper>子标签的class属性
String mapperClass = child.getStringAttribute("class");
// 它们是互斥的
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
// 专门用来解析mapper映射文件
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
// 通过XMLMapperBuilder解析mapper映射文件
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
// 通过XMLMapperBuilder解析mapper映射文件
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
Class<?> mapperInterface = Resources.classForName(mapperClass);
// 将指定mapper接口以及它的代理对象存储到一个Map集合中,key为mapper接口类型,value为代理对象工厂
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
# <package>
子标签
# 1. Configuration#addMappers
将包下所有的mapper接口以及它的代理对象存储到一个Map集合中,key为mapper接口类型,value为代理对象工厂
public void addMappers(String packageName) {
mapperRegistry.addMappers(packageName);
}
# 1.1 MapperRegistry#addMappers
将Mapper接口添加到MapperRegistry中
//1
public void addMappers(String packageName) {
addMappers(packageName, Object.class);
}
//2
public void addMappers(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
// 根据package名称,加载该包下Mapper接口文件(不是映射文件)
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
// 获取加载的Mapper接口
Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
for (Class<?> mapperClass : mapperSet) {
// 将Mapper接口添加到MapperRegistry中
addMapper(mapperClass);
}
}
//3
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
// 如果Map集合中已经有该mapper接口的映射,就不需要再存储了
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
// 将mapper接口以及它的代理对象存储到一个Map集合中,key为mapper接口类型,value为代理对象工厂
knownMappers.put(type, new MapperProxyFactory<T>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the
// mapper parser. If the type is already known, it won't try.
// 用来解析注解方式的mapper接口
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
// 解析注解方式的mapper接口
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
# 1.1.1 MapperAnnotationBuilder#parse
解析注解方式的mapper接口
public void parse() {
// 获取mapper接口的全路径
String resource = type.toString();
// 是否解析过该mapper接口
if (!configuration.isResourceLoaded(resource)) {
// 先解析mapper映射文件
loadXmlResource();
// 设置解析标识
configuration.addLoadedResource(resource);
// Mapper构建者助手
assistant.setCurrentNamespace(type.getName());
// 解析CacheNamespace注解
parseCache();
// 解析CacheNamespaceRef注解
parseCacheRef();
Method[] methods = type.getMethods();
for (Method method : methods) {
try {
// issue #237
if (!method.isBridge()) {
// 每个mapper接口中的方法,都解析成MappedStatement对象
parseStatement(method);
}
} catch (IncompleteElementException e) {
configuration.addIncompleteMethod(new MethodResolver(this, method));
}
}
}
//去检查所有的incompleteMethods,如果可以解析了.那就移除
parsePendingMethods();
}
# 1.1.1.1 MapperAnnotationBuilder#parseStatement
每个mapper接口中的方法,都解析成MappedStatement对象
void parseStatement(Method method) {
// 获取Mapper接口的形参类型
Class<?> parameterTypeClass = getParameterType(method);
// 解析Lang注解
LanguageDriver languageDriver = getLanguageDriver(method);
//
SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);
if (sqlSource != null) {
Options options = method.getAnnotation(Options.class);
// 组装mappedStatementId
final String mappedStatementId = type.getName() + "." + method.getName();
Integer fetchSize = null;
Integer timeout = null;
StatementType statementType = StatementType.PREPARED;
ResultSetType resultSetType = null;
// 获取该mapper接口中的方法是CRUD操作的哪一种
SqlCommandType sqlCommandType = getSqlCommandType(method);
// 是否是SELECT操作
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = !isSelect;
boolean useCache = isSelect;
// 主键生成器,用于主键返回
KeyGenerator keyGenerator;
String keyProperty = null;
String keyColumn = null;
if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
// first check for SelectKey annotation - that overrides everything else
SelectKey selectKey = method.getAnnotation(SelectKey.class);
if (selectKey != null) {
keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver);
keyProperty = selectKey.keyProperty();
} else if (options == null) {
keyGenerator = configuration.isUseGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
} else {
keyGenerator = options.useGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
keyProperty = options.keyProperty();
keyColumn = options.keyColumn();
}
} else {
keyGenerator = NoKeyGenerator.INSTANCE;
}
if (options != null) {
if (FlushCachePolicy.TRUE.equals(options.flushCache())) {
flushCache = true;
} else if (FlushCachePolicy.FALSE.equals(options.flushCache())) {
flushCache = false;
}
useCache = options.useCache();
fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; //issue #348
timeout = options.timeout() > -1 ? options.timeout() : null;
statementType = options.statementType();
resultSetType = options.resultSetType();
}
// 处理ResultMap注解
String resultMapId = null;
ResultMap resultMapAnnotation = method.getAnnotation(ResultMap.class);
if (resultMapAnnotation != null) {
String[] resultMaps = resultMapAnnotation.value();
StringBuilder sb = new StringBuilder();
for (String resultMap : resultMaps) {
if (sb.length() > 0) {
sb.append(",");
}
sb.append(resultMap);
}
resultMapId = sb.toString();
} else if (isSelect) {
resultMapId = parseResultMap(method);
}
// 通过Mapper构建助手,创建一个MappedStatement对象,封装信息
assistant.addMappedStatement(
mappedStatementId,
sqlSource,
statementType,
sqlCommandType,
fetchSize,
timeout,
// ParameterMapID
null,
parameterTypeClass,
resultMapId,
getReturnType(method),
resultSetType,
flushCache,
useCache,
// TODO gcode issue #577
false,
keyGenerator,
keyProperty,
keyColumn,
// DatabaseID
null,
languageDriver,
// ResultSets
options != null ? nullOrEmpty(options.resultSets()) : null);
}
}
# 1.1.1.1.2 MapperBuilderAssistant#addMappedStatement
通过Mapper构建助手,创建一个MappedStatement对象,封装信息
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,用于创建MappedStatement对象
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.Builder,构建一个MappedStatement
MappedStatement statement = statementBuilder.build();
// 将MappedStatement对象存储到Configuration中的Map集合中,key为statement的id,value为MappedStatement对象
configuration.addMappedStatement(statement);
return statement;
}
# <mapper>
子标签
# 1.XMLMapperBuilder#构造函数
专门用来解析mapper映射文件
public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
configuration, resource, sqlFragments);
}
# 1.1 XPathParser#构造函数
用来使用XPath语法解析XML的解析器
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
// 解析XML文档为Document对象
this.document = createDocument(new InputSource(inputStream));
}
# 1.1.1 XPathParser#createDocument
创建Mapper映射文件对应的Document对象
private Document createDocument(InputSource inputSource) {
// important: this must only be called AFTER common constructor
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 进行dtd或者Schema校验
factory.setValidating(validation);
factory.setNamespaceAware(false);
// 设置忽略注释为true
factory.setIgnoringComments(true);
// 设置是否忽略元素内容中的空白
factory.setIgnoringElementContentWhitespace(false);
factory.setCoalescing(false);
factory.setExpandEntityReferences(true);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(entityResolver);
builder.setErrorHandler(new ErrorHandler() {
@Override
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void warning(SAXParseException exception) throws SAXException {
}
});
// 通过dom解析,获取Document对象
return builder.parse(inputSource);
} catch (Exception e) {
throw new BuilderException("Error creating document instance. Cause: " + e, e);
}
}
# 1.2 XMLMapperBuilder#构造函数
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;
}
# 1.2.1MapperBuilderAssistant#构造函数
用于构建MappedStatement对象的
public MapperBuilderAssistant(Configuration configuration, String resource) {
super(configuration);
ErrorContext.instance().resource(resource);
this.resource = resource;
}
# 2. XMLMapperBuilder#parse
通过XMLMapperBuilder解析mapper映射文件
public void parse() {
// mapper映射文件是否已经加载过
if (!configuration.isResourceLoaded(resource)) {
// 从映射文件中的<mapper>根标签开始解析,直到完整的解析完毕
configurationElement(parser.evalNode("/mapper"));
// 标记已经解析
configuration.addLoadedResource(resource);
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
# 2.1 XMLMapperBuilder#configurationElement
从映射文件中的根标签开始解析,直到完整的解析完毕
/**
* 解析映射文件
* @param context 映射文件根节点<mapper>对应的XNode
*/
private void configurationElement(XNode context) {
try {
// 获取<mapper>标签的namespace值,也就是命名空间
String namespace = context.getStringAttribute("namespace");
// 命名空间不能为空
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
// 设置当前的命名空间为namespace的值
builderAssistant.setCurrentNamespace(namespace);
// 解析<cache-ref>子标签
cacheRefElement(context.evalNode("cache-ref"));
// 解析<cache>子标签
cacheElement(context.evalNode("cache"));
// 解析<parameterMap>子标签
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
// 解析<resultMap>子标签
resultMapElements(context.evalNodes("/mapper/resultMap"));
// 解析<sql>子标签,也就是SQL片段
sqlElement(context.evalNodes("/mapper/sql"));
// 解析<select>\<insert>\<update>\<delete>子标签
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);
}
}
# 2.1.1 XMLMapperBuilder#buildStatementFromContext
用来创建MappedStatement对象的
//1、构建MappedStatement
private void buildStatementFromContext(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
// 构建MappedStatement
buildStatementFromContext(list, null);
}
//2、专门用来解析MappedStatement
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
// MappedStatement解析器
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
// 解析select等4个标签,创建MappedStatement对象
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
# 2.1.1.1 XMLStatementBuilder#构造函数
专门用来解析MappedStatement
public XMLStatementBuilder(Configuration configuration, MapperBuilderAssistant builderAssistant, XNode context, String databaseId) {
super(configuration);
this.builderAssistant = builderAssistant;
this.context = context;
this.requiredDatabaseId = databaseId;
}
# 2.1.1.2 XMLStatementBuilder#parseStatementNode
解析子标签
/**
* 解析子标签
*/
public void parseStatementNode() {
// 获取statement的id属性(特别关键的值)
String id = context.getStringAttribute("id");
String databaseId = context.getStringAttribute("databaseId");
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
// 获取入参类型
String parameterType = context.getStringAttribute("parameterType");
// 别名处理,获取入参对应的Java类型
Class<?> parameterTypeClass = resolveClass(parameterType);
// 获取ResultMap
String resultMap = context.getStringAttribute("resultMap");
// 获取结果映射类型
String resultType = context.getStringAttribute("resultType");
String lang = context.getStringAttribute("lang");
LanguageDriver langDriver = getLanguageDriver(lang);
// 别名处理,获取返回值对应的Java类型
Class<?> resultTypeClass = resolveClass(resultType);
String resultSetType = context.getStringAttribute("resultSetType");
// 设置默认StatementType为Prepared,该参数指定了后面的JDBC处理时,采用哪种Statement
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
String nodeName = context.getNode().getNodeName();
// 解析SQL命令类型是什么?确定操作是CRUD中的哪一种
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
// <include>标签解析
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
// Parse selectKey after includes and remove them.
// 解析<selectKey>标签
processSelectKeyNodes(id, parameterTypeClass, langDriver);
// Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
// 创建SqlSource,解析SQL,封装SQL语句(未参数绑定)和入参信息
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
String resultSets = context.getStringAttribute("resultSets");
String keyProperty = context.getStringAttribute("keyProperty");
String keyColumn = context.getStringAttribute("keyColumn");
KeyGenerator keyGenerator;
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}
// 通过构建者助手,创建MappedStatement对象
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
# 2.1.1.2.1 MapperBuilderAssistant#addMappedStatement
通过构建者助手,创建MappedStatement对象
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,用于创建MappedStatement对象
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.Builder,构建一个MappedStatement
MappedStatement statement = statementBuilder.build();
// 将MappedStatement对象存储到Configuration中的Map集合中,key为statement的id,value为MappedStatement对象
configuration.addMappedStatement(statement);
return statement;
}
# 2.1.1.2.1.1 MappedStatement.Builder#构造函数
利用构建者模式,去创建MappedStatement.Builder,用于创建MappedStatement对象
public Builder(Configuration configuration, String id, SqlSource sqlSource, SqlCommandType sqlCommandType) {
mappedStatement.configuration = configuration;
mappedStatement.id = id;
mappedStatement.sqlSource = sqlSource;
mappedStatement.statementType = StatementType.PREPARED;
mappedStatement.resultSetType = ResultSetType.DEFAULT;
mappedStatement.parameterMap = new ParameterMap.Builder(configuration, "defaultParameterMap", null, new ArrayList<>()).build();
mappedStatement.resultMaps = new ArrayList<>();
mappedStatement.sqlCommandType = sqlCommandType;
mappedStatement.keyGenerator = configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
String logId = id;
if (configuration.getLogPrefix() != null) {
logId = configuration.getLogPrefix() + id;
}
mappedStatement.statementLog = LogFactory.getLog(logId);
mappedStatement.lang = configuration.getDefaultScriptingLanguageInstance();
}
# 2.1.1.2.1.2 MappedStatement#build
通过MappedStatement.Builder,构建一个MappedStatement
public MappedStatement build() {
assert mappedStatement.configuration != null;
assert mappedStatement.id != null;
assert mappedStatement.sqlSource != null;
assert mappedStatement.lang != null;
mappedStatement.resultMaps = Collections.unmodifiableList(mappedStatement.resultMaps);
return mappedStatement;
}
上次更新: 2023/09/08, 23:19:29