MyBatis注解@Select@Update分析
Posted 叶长风
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis注解@Select@Update分析相关的知识,希望对你有一定的参考价值。
MyBatis注解@Select、@Update分析
前面几篇文章分别分析了Mybatis中的Configuration的配置信息,MyBatis中的Mapper调用等等,在分析配置信息时只是讲了如何解析xml中的sql查询,但是并没有讲怎么解析Mapper中注解对应的SQL,就是如下:
@ResultMap("BaseResultMap")
@Select("select id, username, password, age, mobile, hotel_address from user where id=#id;")
User getUser2(@Param("id") Long id);
这一节就是具体来说如何解析注解,并将其保存进mappedStatements中。
1. 解析configuration
我们回到解析mapper的源码所在,为mapperElement(root.evalNode(“mappers”));在mapperElement方法中,无论是哪一种条件,最终会有一个addMapper的操作,所以这里直接看addMapper操作即可,我们转到最终的addMapper方法。
public <T> void addMapper(Class<T> type)
if (type.isInterface())
if (hasMapper(type))
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
boolean loadCompleted = false;
try
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.
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
finally
if (!loadCompleted)
knownMappers.remove(type);
这个方法中不仅仅做了 knownMappers.put(type, new MapperProxyFactory(type));操作,同时进行了MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);对于注解提供的方法就是在这里开始解析的,我们进入到parse()方法中。
public void parse()
String resource = type.toString();
if (!configuration.isResourceLoaded(resource))
loadXmlResource();
configuration.addLoadedResource(resource);
assistant.setCurrentNamespace(type.getName());
parseCache();
parseCacheRef();
Method[] methods = type.getMethods();
for (Method method : methods)
try
// issue #237
if (!method.isBridge())
parseStatement(method);
catch (IncompleteElementException e)
configuration.addIncompleteMethod(new MethodResolver(this, method));
parsePendingMethods();
进入到parseStatement中,查看解析注释细节,如下:
void parseStatement(Method method)
final String mappedStatementId = type.getName() + "." + method.getName();
//获取到具体SQL
SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);
//获取到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);
//将对应sqlSource以及其他参数保存进Map中
assistant.addMappedStatement(
mappedStatementId,
sqlSource,
statementType,
sqlCommandType,
fetchSize,
timeout,
// ParameterMapID
null,
parameterTypeClass,
resultMapId,
getReturnType(method));
这里根据Mapper所在的包名加上对应解析的方法名,最终组装成mappedStatementId,也就是最终保存进map中的key。
在组装完对应的key、value sqlSource等参数后,调用addMappedStatement进行进一步的包装,再看addMappedStatement方法。
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;
这个方法中在经过将cache、timeout、sql、resource、fetchSize等等参数进行包装后生成MappedStatement对象,最后通过configuration.addMappedStatement(statement)方法,将statement保存进mappedStatements Map中。
对注解形式提供的SQL的分析就到此为止了。
以上是关于MyBatis注解@Select@Update分析的主要内容,如果未能解决你的问题,请参考以下文章
MyBatis源码分析之@SelectProvider注解使用详解