Mybatis可运行源码地址:
- Github:github.com/MrZhang-bad…
- Gitee:gitee.com/ZhangHua-Ba…
该项目包含
- Mybatis源码
- com.github.PageHelper源码
大家可以在学习MyBatis源码的插件部分的时候直接配置PageHelper加深对插件开发的理解,运用到工作项目中
一. 概要
1. Mybatis简介
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。 ——来自官方文档
2. 架构设计
3. 运行原理
二. 执行过程详解
1. 获取Session过程
(0)示例
public static SqlSession getSqlSession() throws IOException {
//读取mybatis-config.xml
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//建立SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//获取SqlSession
SqlSession sqlSession = factory.openSession();
return sqlSession;
}
(1)读取配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
- 获取
mybatis-config.xml文件的输入流
(2)根据配置文件生成SqlSessionFactory
build()方法实际调用的是如下方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//根据inputStream封装到XMLConfigBuidler中,用于后面的parser.parase()构建Configuration
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//parse方法返回的是Configuration
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
下面看parse.parse()方法
public Configuration parse() {
//判断是否已经翻译过
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
//入参是经过封装后的XMLConfigBuidler中的XNode节点
private void parseConfiguration(XNode root) {
try {
//依次根绝mybatis-config.xml中的配置开始配置Configuration
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
//这边就是将我们自己写的Plugin注册到Configuration当中
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
//这里是将<mappers></mappers>标签下的所有mapper注册到Configuration中的MapperRegister当中
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
//这边着重看一下解析Plugin和Mapper的代码
//解析Plugin代码
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
//将Plugins标签下所有的Plugin,添加到configuration中
for (XNode child : parent.getChildren()) {
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();
interceptorInstance.setProperties(properties);
//看一下这边代码
configuration.addInterceptor(interceptorInstance);
}
}
}
//Configuration类中,向interceptorChain中添加拦截器(插件)
public void addInterceptor(Interceptor interceptor) {
interceptorChain.addInterceptor(interceptor);
}
//解析Mapper
//这段代码展示的正是mapper配置的四种方式
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
//获取mapper的四种方式
//第一种在<mappers>标签里配置了<package>
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
//获取XXXMapper.xml文件的路径
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
//第二种是在<mappers>标签里配置<mapper resource="xxx/xxx/xxx.xml"/>
ErrorContext.instance().resource(resource);
try(InputStream inputStream = Resources.getResourceAsStream(resource)) {
//读取XXXMapper.xml文件,并且将其封装到XMLMapperBuilder中
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
//根据XXXMapper.xml文件开始翻译
//虽然第二种情况和第三种情况在本函数里都没有addMapper,但是在翻译的过程中都addMapper
mapperParser.parse();
}
} else if (resource == null && url != null && mapperClass == null) {
//第三种是
ErrorContext.instance().resource(url);
try(InputStream inputStream = Resources.getUrlAsStream(url)){
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
}
} else if (resource == null && url == null && mapperClass != null) {
//第四种是在<mappers>标签内部使用<mapper class="com.example.demo.mapper.XXXMapper/>
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.");
}
}
}
}
}
接着看一下build方法中的build(parse.parse())
//根据Configuration生成一个默认SqlSessionFactory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
(3)SqlSessionFactory获取SqlSession
SqlSession sqlSession = factory.openSession();
//openSession()实际调用的是DefaultSqlSessionFactory中的openSession方法
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//生成执行器
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//着重看一下生成执行器的方法
//如果自定义了插件,也是在这里添加的
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
//如果executorType为null,那么就设置为默认的SimpleExecutor
executorType = executorType == null ? defaultExecutorType : executorType;
//上面定义defalutExecutor的时候已经将其赋值为SIMPLE,defaultExecutor已经不为null
//下面这行代码永远返回的是executorType,不会走到ExecutorType.SIMPLE,这边存疑
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
/**
* 对于所有拦截器中拦截Executor的插件进行添加
*/
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
2. 获取Mapper过程
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
- 实际调用SqlSession的实现类DefaultSqlSession中的getMapper方法
- 并且这边返回的UserMapper是一个UserMapper代理类,是“增强过”的UserMapper
@Override
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
//看一下Configuration中的getMapper方法
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//之前在XMLMapperBuilder的时候,把Mapper存到了Confuguration中的mapperRegistry当中
//根据XXXMapper.class去mapperRegistry中取出其代理类的工厂类,通过工厂类创建XXXMapper.class的代理类(增强类)
return mapperRegistry.getMapper(type, sqlSession);
}
- 着重看一下mapperRegistry.getMapper(type, sqlSession)方法(重要)
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//之前注册到Configuration中的Registry中的是mapper的过程是
//将mapper对应的MapperProxyFactory存到了这里的knownMappers
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//获取代理工厂类之后,就生成动态代理后的mapper
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);
}
- 现在再回顾一下之前在MapperRegistry中调用的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里的是Mapper的代理工厂类
knownMappers.put(type, new MapperProxyFactory<>(type));
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
//看下代理工厂类
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethodInvoker> 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) {
//创建XXXMapper.class的代理类(增强类)
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
3. 执行过程
List<User> userList = userMapper.selectUsersBySex("m");
(1)进入MapperProxy
//进入XXXMapper.class的代理类,执行"增强"后的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
//调用的是MapperMethodInvoker实现类
//此类是MapperProxy中的静态内部类
private static class PlainMethodInvoker implements MapperMethodInvoker {
private final MapperMethod mapperMethod;
public PlainMethodInvoker(MapperMethod mapperMethod) {
super();
this.mapperMethod = mapperMethod;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
return mapperMethod.execute(sqlSession, args);
}
}
(2)进入MapperMethod
//采用命令模式
//根据Sql命令的类型,选择相应的执行方法
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
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 = Optional.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;
}
//看下MapperMethod类下的executeForMany方法
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
List<E> result;
/**
* 这边实际返回的是一个map,应该是XXXMapper中的一个方法,将入参,转化为key和value
* 比如
* public List<User> selectUsersByDepartmentIdAndArea(@para("departmentId" Stri
* 也可以是
* public List<User> selectUsersBySex(String sex)
*/
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
result = sqlSession.selectList(command.getName(), param, rowBounds);
} else {
//进入这个方法
result = sqlSession.selectList(command.getName(), param);
}
if (!method.getReturnType().isAssignableFrom(result.getClass())) {
if (method.getReturnType().isArray()) {
return convertToArray(result);
} else {
return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
}
}
return result;
}
(3)进入SqlSession的实现类DefaultSqlSession类
//到了SqlSession中的selectList方法
@Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
return selectList(statement, parameter, rowBounds, Executor.NO_RESULT_HANDLER);
}
//最终实际调用的是这个方法
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
//如果定义了拦截Executor的拦截器的话,Executor即将被Plugin拦截
return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
(4)进入CacheExecutor
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
/**
* getBoundSql(parameterObject),根据查询函数的入参对<mapper></mapper>标签里
* 例如<if></if>这些标签构建SQL语句 select * from xxx where id = ? 这种
*/
BoundSql boundSql = ms.getBoundSql(parameterObject);
//创建本地缓存的Key
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
//执行query进入下面的方法
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
//执行到这边
//这边之前根据Configuration配置好了执行器是SimpleExecutor
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
(5)进入BaseExecutor
- 其实delegate代理的是SimpleExecutor
- 但是调用的这个方法是其父类BaseExecutor中的,所以进入了BaseExecutor
@Override
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 {
//进如该方法
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;
}
//调用本类的queryFromDatabase方法
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
//将本次查询的Key存放在本地缓存当中
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
//将Key删除,为后面将Key和list放入本地缓存做铺垫
localCache.removeObject(key);
}
//将查询结果放入本地缓存中,方便再次调用
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
(6)进入SimpleExecutor
@Override
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();
//SQL语句处理器
//在这过程中,创建了ParameterHandle和ResultSetHandler
//如果定义了相关插件
//也会添加拦截StatementHandler、ParameterHandler、ResultSetHandler的插件
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//这边就准备好了要执行的stmt
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
//看一下prepareStatementHandler(handler, ms.getStatementLog())
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
/**
* 这边获取连接conn,如数数据源设置的是pooled,如果数据库连接池中可以获取连接就从连接池中获取
* 如果没有的话,就创建一个连接,并且放到连接池中
*/
Connection connection = getConnection(statementLog);
//根据connection,处理并获取statement
//这边的stmt是实际上是一个PrepareStatement
stmt = handler.prepare(connection, transaction.getTimeout());
//处理参数并且放到PrepareStatement里面
handler.parameterize(stmt);
return stmt;
}
//下面看一下handler.parameterize(stms)
(7)进入PreparedStatementHandler
//经过RoutingStatementHandler路由到PrepareStatementHandler
@Override
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
//调用之前设置的DefaultStatementHandler对参数进行处理
public void setParameters(PreparedStatement ps) {
//根据SQL语句中的参数,对参数类型进行处理,然后放到PrepareHandler当中
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
//获取mapper文件传入的参数,按照传入顺序
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
//将参数设置到PrepareStatement中
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
(8)回到SimpleExecutor
- 此时可看到之前BoundSql是
- 执行handler.parameterize(stms)之后
com.mysql.cj.jdbc.ClientPreparedStatement: select * from t_user where sex = 'm'
(9)进入PreparedStatementHandler
- 从SimpleExecutor调用RoutingStatementHandler路由到PrepareStatementHandler
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
//对返回结果进行处理
return resultSetHandler.handleResultSets(ps);
}
//下面看对结果的处理
(10)进入DefaultResultSetHandler
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
ResultSetWrapper rsw = getFirstResultSet(stmt);
//返回之前XXXMapper.xml文件中定义的resultType
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
//处理第一个结果集
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
//处理单个结果集
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
String[] resultSets = mappedStatement.getResultSets();
//不止一个结果集
if (resultSets != null) {
//处理剩余结果集
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
//处理单个结果集
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
//如果是单个结果集,就直接返回这个结果集中对应的查询数据行的结果List
return collapseSingleResultList(multipleResults);
}
三. 总结
汇总图
- 如果图片不能正常显示的话,进入如下连接观看 Mybatis汇总图