Mybatis源码-SqlSession执行Mapper过程
目录
Mapper由两部分组成,分别为Mapper接口和通过注解或者XML文件配置的SQL语句。主要分为4个部分讲解:
- Mapper接口的注册过程
- MappedStatement对象的注册过程
- Mapper方法的调用过程
- SqlSession执行Mapper的过程
Mapper接口的注册过程 #
// 获取UserMapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 执行Mapper方法,获取执行结果
List<UserEntity> userList = userMapper.listAllUser();
我们知道,接口中定义的方法必须通过某个类实现该接口,然后创建该类的实例,才能通过实例调用方法。所以 SqlSession对象的getMapper()方法返回的一定是某个类的实例。getMapper()方法返回的是一个动态代理对象。
MyBatis中通过MapperProxy类实现动态代理。MapperProxy使用的是JDK内置的动态代理,实现了InvocationHandler接口,invoke()方法中为通用的拦截逻辑,具体内容在介绍Mapper方法调用过程时再做介绍。
public class MapperProxy<T> implements InvocationHandler, Serializable {
// .....
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 从Object类继承的方法不做处理
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
// 对Mapper接口中定义的方法进行封装,生成MapperMethod对象
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
}
使用JDK内置动态代理,通过MapperProxy类实现InvocationHandler接口,定义方法执行拦截逻辑后,还需要调用java.lang.reflect.Proxy类的newProxyInstance()方法创建代理对象。MyBatis对这一过程做了封装,使用MapperProxyFactory创建Mapper动态代理对象。
MapperProxyFactory代码如下:
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
MapperProxyFactory类的工厂方法newInstance()是非静态的。也就是说,使用MapperProxyFactory 创建Mapper 动态代理对象首先需要创建MapperProxyFactory实例。MapperProxyFactory实例是什么时候创建的呢?
MyBatis通过mapperRegistry属性注册Mapper接口与MapperProxyFactory对象之间的对应关系。下面是MapperRegistry类的关键代码:
public class MapperRegistry {
// Configuration对象引用
private final Configuration config;
// 用于注册Mapper接口Class对象,和MapperProxyFactory对象对应关系
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
public MapperRegistry(Configuration config) {
this.config = config;
}
// 根据Mapper接口Class对象获取Mapper动态代理对象
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
public <T> boolean hasMapper(Class<T> type) {
return knownMappers.containsKey(type);
}
// 根据Mapper接口Class对象,创建MapperProxyFactory对象,并注册到knownMappers属性中
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);
}
}
}
}
// ..
}
MyBatis 框架在应用启动时会解析所有的Mapper接口,然后调用MapperRegistry 对象的addMapper()方法将Mapper接口信息和对应的MapperProxyFactory对象注册到MapperRegistry对象中。
MappedStatement对象的注册过程 #
MyBatis通过MappedStatement类描述Mapper的SQL配置信息。SQL配置有两种方式:一种是通过XML文件配置;另一种是通过Java注解,而Java注解的本质就是一种轻量级的配置信息。
Configuration中有一个mappedStatements 属性,用于注册所有的MappedStatement对象
protected final Map<String, MappedStatement> mappedStatements =
new StrictMap<MappedStatement>("Mapped Statements collection");
mappedStatements属性是一个Map对象,它的Key为Mapper SQL配置的Id,如果SQL是通过XML配置的,则 Id为命名空间加上<select/update/delete/insert>标签的 Id,如果 SQL通过Java注解配置,则Id为Mapper接口的完全限定名(包括包名)加上方法名称。
想要了解MappedStatement对象的创建过程,就必须重点关注<mappers>标签的解析过程。<mappers>标签是通过XMLConfigBuilder 类的mapperElement()方法来解析的。下面是mapperElement()方法的实现:
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
// 通过<package>标签指定包名
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
// 通过resource属性指定XML文件路径
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
// 通过url属性指定XML文件路径
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
// 通过class属性指定接口的完全限定名
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
对应如下几种方式的mapper定义:
以<mapper resourcer="./>
这种形式为例介绍MapperSQL配置文件的解析过程。
Mapper SQL配置文件的解析需要借助XMLMapperBuilder对象。在mapperElement()方法中,首先创建一个XMLMapperBuilder对象,然后调用XMLMapperBuilder对象的parse()方法完成解析,该方法内容如下:
public void parse() {
if (!configuration.isResourceLoaded(resource)) {
// 调用XPathParser的evalNode()方法获取根节点对应的XNode对象
configurationElement(parser.evalNode("/mapper"));
// 將资源路径添加到Configuration对象中
configuration.addLoadedResource(resource);
bindMapperForNamespace();
}
// 继续解析之前解析出现异常的ResultMap对象
parsePendingResultMaps();
// 继续解析之前解析出现异常的CacheRef对象
parsePendingCacheRefs();
// 继续解析之前解析出现异常<select|update|delete|insert>标签配置
parsePendingStatements();
}
private void configurationElement(XNode context) {
try {
// 获取命名空间
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
// 设置当前正在解析的Mapper配置的命名空间
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>标签
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);
}
}
// 重点关注解析所有的<select|insert|update|delete>标签
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
// 通过XMLStatementBuilder对象,对<select|update|insert|delete>标签进行解析
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
// 调用parseStatementNode()方法解析
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
// 真正的解析方法
public void parseStatementNode() {
String id = context.getStringAttribute("id");
String databaseId = context.getStringAttribute("databaseId");
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}
// 解析<select|update|delete|insert>标签属性
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
String parameterType = context.getStringAttribute("parameterType");
Class<?> parameterTypeClass = resolveClass(parameterType);
String resultMap = context.getStringAttribute("resultMap");
String resultType = context.getStringAttribute("resultType");
// 获取LanguageDriver对象
String lang = context.getStringAttribute("lang");
LanguageDriver langDriver = getLanguageDriver(lang);
// 获取Mapper返回结果类型Class对象
Class<?> resultTypeClass = resolveClass(resultType);
String resultSetType = context.getStringAttribute("resultSetType");
// 默认Statement类型为PREPARED
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType",
StatementType.PREPARED.toString()));
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
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>标签内容,替换为<sql>标签定义的SQL片段
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
// 解析<selectKey>标签
processSelectKeyNodes(id, parameterTypeClass, langDriver);
// 通过LanguageDriver解析SQL内容,生成SqlSource对象
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;
}
// MapperBuilderAssistant对象用于生成 MappedStatement 对象
// 最终会调用 configuration.addMappedStatement(statement);方法
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
Mapper方法的调用过程 #
Mapper代理对象MapperProxy的invoke执行过程:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 从Object类继承的方法不做处理
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
// 对Mapper接口中定义的方法进行封装,生成MapperMethod对象
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
MapperMethod类是对Mapper方法相关信息的封装,通过MapperMethod能够很方便地获取SQL语句的类型、方法的签名信息等。
public class MapperMethod {
private final SqlCommand command;
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
// ...
}
// SqlCommand的解析和创建过程
public static class SqlCommand {
private final String name; // Mapper Id
private final SqlCommandType type; // SQL类型
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
final String methodName = method.getName();
// 获取声明该方法的类或接口的Class对象
final Class<?> declaringClass = method.getDeclaringClass();
// 获取描述<select|update|insert|delete>标签的MappedStatement对象
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
if (ms == null) {
if (method.getAnnotation(Flush.class) != null) {
name = null;
type = SqlCommandType.FLUSH;
} else {
throw new BindingException("Invalid bound statement (not found): "
+ mapperInterface.getName() + "." + methodName);
}
} else {
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}
private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
Class<?> declaringClass, Configuration configuration) {
// 获取Mapper的Id
String statementId = mapperInterface.getName() + "." + methodName;
if (configuration.hasStatement(statementId)) {
// 如果Configuration对象中已经注册了MappedStatement对象,则获取该MappedStatement对象
return configuration.getMappedStatement(statementId);
} else if (mapperInterface.equals(declaringClass)) {
return null;
}
// 如果方法是在Mapper父接口中定义,则根据父接口获取对应的MappedStatement对象
for (Class<?> superInterface : mapperInterface.getInterfaces()) {
if (declaringClass.isAssignableFrom(superInterface)) {
MappedStatement ms = resolveMappedStatement(superInterface, methodName,
declaringClass, configuration);
if (ms != null) {
return ms;
}
}
}
return null;
}
}
// MethodSignature的解析和创建过程
//(1)获取Mapper方法的返回值类型,具体是哪种类型,通过boolean类型的属性进行标记。
//(2)记录RowBounds参数位置,用于处理后续的分页查询,同时记录ResultHandler参数位置,用于处理从数据库中检索的每一行数据。
//(3)创建ParamNameResolver对象。ParamNameResolver对象用于解析Mapper方法中的参数名称及参数注解信息。
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
// 获取方法返回值类型
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
if (resolvedReturnType instanceof Class<?>) {
this.returnType = (Class<?>) resolvedReturnType;
} else if (resolvedReturnType instanceof ParameterizedType) {
this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
} else {
this.returnType = method.getReturnType();
}
// 返回值类型为void
this.returnsVoid = void.class.equals(this.returnType);
// 返回值类型为集合
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
// 返回值类型为Cursor
this.returnsCursor = Cursor.class.equals(this.returnType);
// 返回值类型为Optional
this.returnsOptional = Jdk.optionalExists && Optional.class.equals(this.returnType);
this.mapKey = getMapKey(method);
// 返回值类型为Map
this.returnsMap = this.mapKey != null;
// RowBounds参数位置索引
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
// ResultHandler参数位置索引
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
// ParamNameResolver用于解析Mapper方法参数
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
在ParamNameResolver构造方法中,对所有Mapper方法的所有参数信息进行遍历,首先判断参数中是否有@Param注解,如果包含@Param注解,就从注解中获取参数名称,如果参数中没有@Param注解,就根据MyBatis主配置文件中的useActualParamName参数确定是否获取实际方法定义的参数名称,若useActualParamName参数值为true,则使用方法定义的参数名称。解析完毕后,将参数信息保存在一个不可修改的names 属性中,该属性是一个SortedMap<Integer,String>类型的对象。
public ParamNameResolver(Configuration config, Method method) {
// 获取所有参数类型
final Class<?>[] paramTypes = method.getParameterTypes();
// 获取所有参数注解
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final SortedMap<Integer, String> map = new TreeMap<Integer, String>();
int paramCount = paramAnnotations.length;
// 从@Param 注解中获取参数名称
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
if (isSpecialParameter(paramTypes[paramIndex])) {
continue;
}
String name = null;
for (Annotation annotation : paramAnnotations[paramIndex]) {
// 方法参数中,是否有Param注解
if (annotation instanceof Param) {
hasParamAnnotation = true;
// 获取参数名称
name = ((Param) annotation).value();
break;
}
}
if (name == null) {
// 未指定@Param 注解,这判断是否使用实际的参数名称,参考useActualParamName属性的作用
if (config.isUseActualParamName()) {
// 获取参数名
name = getActualParamName(method, paramIndex);
}
if (name == null) {
name = String.valueOf(map.size());
}
}
// 將参数信息存放在Map中,Key为参数位置索引,Value为参数名称
map.put(paramIndex, name);
}
// 將参数信息保存在names属性中
names = Collections.unmodifiableSortedMap(map);
}
MapperMethod对象创建完成之后,会调用execute()方法。
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
// 其中command为MapperMethod构造是创建的SqlCommand对象
// 获取SQL语句类型
switch (command.getType()) {
case INSERT: {
// 获取参数信息
Object param = method.convertArgsToSqlCommandParam(args);
// 调用SqlSession的insert()方法,然后调用rowCountResult()方法统计行数
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
// 调用SqlSession对象的update()方法
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional() &&
(result == null || !method.getReturnType().equals(result.getClass()))) {
result = OptionalUtil.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
SqlSession执行Mapper的过程 #
上一节介绍了Mapper方法的调用过程。我们了解到,**MyBatis通过动态代理将Mapper方法的调用转换为调用SqlSession提供的增删改查方法,以Mapper的Id作为参数,执行数据库的增删改查操作。以SqlSession.selectList()**追踪
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// 根据Mapper的Id,获取对应的MappedStatement对象
MappedStatement ms = configuration.getMappedStatement(statement);
// 以MappedStatement对象作为参数,调用Executor的query()方法
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//Executor的query()方法,这里使用了一级缓存
// org.apache.ibatis.executor.BaseExecutor#createCacheKey可以看看缓存的key是怎么创建的。
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 获取BoundSql对象,BoundSql是对动态SQL解析生成的SQL语句和参数映射信息的封装
BoundSql boundSql = ms.getBoundSql(parameter);
// 创建CacheKey,用于缓存Key
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
// 调用重载的query()方法
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
// 从缓存中获取结果
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
// 缓存中获取不到,则调用queryFromDatabase()方法从数据库中查询
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
// 调用doQuery()方法查询
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
// 缓存查询结果
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
// SimpleExecutor.doQuery()
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
// 获取StatementHandler对象
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 调用prepareStatement()方法,创建Statement对象,并进行设置参数等操作
stmt = prepareStatement(handler, ms.getStatementLog());
// 调用StatementHandler对象的query()方法执行查询操作
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
// SimpleStatementHandler
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
// 真正调用JDBC的API
statement.execute(sql);
return resultSetHandler.<E>handleResultSets(statement);
}