Mybatis操作数据库流程源码

Java操作数据库需要经过3个大步骤:

  1. 获取数据库连接
  2. 执行SQL语句
  3. 关闭数据库连接

Mybatis将这几个步骤进行了封装,将获取数据库连接的给工作交给了SqlSessionFactory,将执行SQL的工作交给了SqlSession。

1 获取SqlSession#

在程序启动时,会根据配置创建SqlSessionFactory:

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

SqlSessionFactory是一个工厂,在整个程序中应该是单例的存在。它会保存所有配置信息,需要操作数据库时,通过调用SqlSessionFactory#openSession()方法,可以根据配置信息生成新的SqlSession。

SqlSessionFactory#openSessionFromDataSource()展示了创建SqlSession的流程,本质上只是创建了Executor对象,并对其进行了封装:

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();
}
}
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();
  }
}
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(); } }

需要注意的是,Configuration#newExecutor()方法会对执行器进行缓存代理和插件代理。默认情况下,生成从外到内Interceptor -> CachingExecutor -> SimpleExecutor的层级结构:

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
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) interceptorChain.pluginAll(executor);
return executor;
}
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
  executorType = executorType == null ? defaultExecutorType : executorType;
  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) interceptorChain.pluginAll(executor);
  return executor;
}
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; 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) interceptorChain.pluginAll(executor); return executor; }

2 执行SQL语句#

Mybatis提供了两种执行SQL的方式:

  1. 根据statementId执行
  2. 使用映射接口代理对象执行

2.1 根据statementId执行#

SqlSession提供了selectXxx/insert/update/delete等方法操作数据库。

默认情况下,DefaultSqlSession会将selectXxx(除了selectCursor)方法统一交给selectList方法处理,将insert/update/delete方法统一交给update方法处理。它们的处理方式相同:

  1. 从Configuration中获取对应的MappedStatement
  2. 使用Executor执行SQL

DefaultSqlSession#selectList:

private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
  try {
    MappedStatement ms = configuration.getMappedStatement(statement);
    return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { try { MappedStatement ms = configuration.getMappedStatement(statement); return executor.query(ms, wrapCollection(parameter), rowBounds, handler); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }

DefaultSqlSession#update:

public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
public int update(String statement, Object parameter) {
  try {
    dirty = true;
    MappedStatement ms = configuration.getMappedStatement(statement);
    return executor.update(ms, wrapCollection(parameter));
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}
public int update(String statement, Object parameter) { try { dirty = true; MappedStatement ms = configuration.getMappedStatement(statement); return executor.update(ms, wrapCollection(parameter)); } catch (Exception e) { throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }

2.2.1 Executor#selectList#

除了自定义Interceptor,首先会进入到CachingExecutor#query方法,它主要对全局缓存进行了处理:

  1. 根据查询条件(包括id、offset、limit、sql、查询参数和environmentId)创建CacheKey
  2. 获取MappedStatement的缓存对象Cache
  3. 从Cache中获取查询条件对应的缓存:如果有缓存,直接返回;如果没有缓存,进一步查询,并添加缓存

CachingExecutor#query:

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;
}
}
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
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;
    }
  }
  return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
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; } } return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }

之所以说CachingExecutor#query方法处理的是全局缓存,是因为这个缓存存在于MappedStatement,是所有会话共享的对象。

接着,会执行BaseExecutor#query方法,它主要对会话缓存进行处理:

  1. 从执行器localCache中获取查询条件对应的缓存
  2. 如果有缓存,直接返回;如果没有缓存,进一步查询数据库,并添加缓存

之所以说BaseExecutor#query方法处理的是会话缓存,是应为这个缓存存在于BaseExecutor,只有当前SqlSession才可以访问。

BaseExecutor#query和BaseExecutor#queryFromDatabase:

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();
}
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
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 {
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;
}
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();
    }
    deferredLoads.clear();
    if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
      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 {
    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;
}
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(); } deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { 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 { 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执行步骤如下:

  1. 创建StatementHandler
  2. 创建Statement(参数解析)
  3. 执行Statement
  4. 结果集封装

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);
// 创建Statement(参数解析)
stmt = prepareStatement(handler, ms.getStatementLog());
// 执行Statement&结果集封装
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
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);
    // 创建Statement(参数解析)
    stmt = prepareStatement(handler, ms.getStatementLog());
    // 执行Statement&结果集封装
    return handler.query(stmt, resultHandler);
  } finally {
    closeStatement(stmt);
  }
}
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); // 创建Statement(参数解析) stmt = prepareStatement(handler, ms.getStatementLog()); // 执行Statement&结果集封装 return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } }

默认会创建RoutingStatementHandler,它只是一个代理对象,会根据MappedStatement创建具体SimpleStatementHandler/PreparedStatementHandler/CallableStatementHandler实现类。

在创建StatementHandler过程中,还会使用Interceptor进行代理,因此最终返回的对象是Interceptor -> RoutingStatementHandler -> 具体实现类的层级结构。

默认情况下,创建的StatementHandler具体实现类一般是PreparedStatementHandler。

BaseStatementHandler是SimpleStatementHandler/PreparedStatementHandler/CallableStatementHandler的共同父类,它的构造函数会创建ParameterHander和ResultSetHandler对象(并使用插件代理),用于参数解析和结果集封装。

Configuration#newStatementHandler、RoutingStatementHandler构造函数和BaseStatementHandler构造函数:

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 创建RoutingStatementHandler
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
// 使用插件代理
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
if (boundSql == null) { // issue #435, get the key before calculating the statement
generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  // 创建RoutingStatementHandler
  StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
  // 使用插件代理
  statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
  return statementHandler;
}

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  switch (ms.getStatementType()) {
    case STATEMENT:
      delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
      break;
    case PREPARED:
      delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
      break;
    case CALLABLE:
      delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
      break;
    default:
      throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
  }
}

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  this.configuration = mappedStatement.getConfiguration();
  this.executor = executor;
  this.mappedStatement = mappedStatement;
  this.rowBounds = rowBounds;
  this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
  this.objectFactory = configuration.getObjectFactory();
  if (boundSql == null) { // issue #435, get the key before calculating the statement
    generateKeys(parameterObject);
    boundSql = mappedStatement.getBoundSql(parameterObject);
  }
  this.boundSql = boundSql;
  this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
  this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { // 创建RoutingStatementHandler StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); // 使用插件代理 statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; } public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { switch (ms.getStatementType()) { case STATEMENT: delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case PREPARED: delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; case CALLABLE: delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); break; default: throw new ExecutorException("Unknown statement type: " + ms.getStatementType()); } } protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { this.configuration = mappedStatement.getConfiguration(); this.executor = executor; this.mappedStatement = mappedStatement; this.rowBounds = rowBounds; this.typeHandlerRegistry = configuration.getTypeHandlerRegistry(); this.objectFactory = configuration.getObjectFactory(); if (boundSql == null) { // issue #435, get the key before calculating the statement generateKeys(parameterObject); boundSql = mappedStatement.getBoundSql(parameterObject); } this.boundSql = boundSql; this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql); this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql); }

SimpleExecutor#prepareStatement会创建Statement,并设置参数:

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
// 创建Statement
stmt = handler.prepare(connection, transaction.getTimeout());
// 设置参数
handler.parameterize(stmt);
return stmt;
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
  Statement stmt;
  Connection connection = getConnection(statementLog);
  // 创建Statement
  stmt = handler.prepare(connection, transaction.getTimeout());
  // 设置参数
  handler.parameterize(stmt);
  return stmt;
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; Connection connection = getConnection(statementLog); // 创建Statement stmt = handler.prepare(connection, transaction.getTimeout()); // 设置参数 handler.parameterize(stmt); return stmt; }

设置参数时,除了自定义Interceptor,默认会执行PreparedStatementHandler#parameterize方法,实际上会调用ParameterHandler(默认是DefaultParameterHandler)进行处理:

  1. 获取参数映射配置信息
  2. 遍历参数映射配置信息,使用TypeHandler设置参数

PreparedStatementHandler#parameterize、DefaultParameterHandler#setParameters和BaseTypeHandler#setParameter:

public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
public void setParameters(PreparedStatement ps) {
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++) {
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 {
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
if (jdbcType == null) {
throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
}
try {
ps.setNull(i, jdbcType.TYPE_CODE);
} catch (SQLException e) {
throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
+ "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
+ "Cause: " + e, e);
}
} else {
try {
setNonNullParameter(ps, i, parameter, jdbcType);
} catch (Exception e) {
throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . "
+ "Try setting a different JdbcType for this parameter or a different configuration property. "
+ "Cause: " + e, e);
}
}
}
public void parameterize(Statement statement) throws SQLException {
  parameterHandler.setParameters((PreparedStatement) statement);
}

public void setParameters(PreparedStatement ps) {
  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++) {
      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 {
          typeHandler.setParameter(ps, i + 1, value, jdbcType);
        } catch (TypeException | SQLException e) {
          throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
        }
      }
    }
  }
}

public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
  if (parameter == null) {
    if (jdbcType == null) {
      throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
    }
    try {
      ps.setNull(i, jdbcType.TYPE_CODE);
    } catch (SQLException e) {
      throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . "
            + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. "
            + "Cause: " + e, e);
    }
  } else {
    try {
      setNonNullParameter(ps, i, parameter, jdbcType);
    } catch (Exception e) {
      throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . "
            + "Try setting a different JdbcType for this parameter or a different configuration property. "
            + "Cause: " + e, e);
    }
  }
}
public void parameterize(Statement statement) throws SQLException { parameterHandler.setParameters((PreparedStatement) statement); } public void setParameters(PreparedStatement ps) { 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++) { 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 { typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException | SQLException e) { throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } } public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { if (parameter == null) { if (jdbcType == null) { throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters."); } try { ps.setNull(i, jdbcType.TYPE_CODE); } catch (SQLException e) { throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " + "Cause: " + e, e); } } else { try { setNonNullParameter(ps, i, parameter, jdbcType); } catch (Exception e) { throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different configuration property. " + "Cause: " + e, e); } } }

接下来,默认情况下使用PreparedStatementHandler#query查询数据库,它会执行Statement,然后使用ResultSetHandler对结果集进行封装:

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.handleResultSets(ps);
}
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  PreparedStatement ps = (PreparedStatement) statement;
  ps.execute();
  return resultSetHandler.handleResultSets(ps);
}
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); return resultSetHandler.handleResultSets(ps); }

ResultSetHandler的默认实现类是DefaultResultSetHandler,处理步骤如下:

  1. 从MappedStatement获取结果集字段映射关系ResultMap
  2. 根据ResultMap,使用ResultHandler对字段进行封装

DefaultResultSetHandler#handleResultSets、DefaultResultSetHandler#handleResultSet、DefaultResultSetHandler#handleRowValues、DefaultResultSetHandler#handleRowValuesForSimpleResultMap:

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);
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++;
}
}
return collapseSingleResultList(multipleResults);
}
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults,
ResultMapping parentMapping) throws SQLException {
try {
if (parentMapping != null) {
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
} else if (resultHandler == null) {
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
multipleResults.add(defaultResultHandler.getResultList());
} else {
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
} finally {
closeResultSet(rsw.getResultSet());
}
}
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,
RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
if (resultMap.hasNestedResultMaps()) {
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
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);

  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++;
    }
  }
  return collapseSingleResultList(multipleResults);
}

private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults,
    ResultMapping parentMapping) throws SQLException {
  try {
    if (parentMapping != null) {
      handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
    } else if (resultHandler == null) {
      DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
      handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
      multipleResults.add(defaultResultHandler.getResultList());
    } else {
      handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
    }
  } finally {
    closeResultSet(rsw.getResultSet());
  }
}

public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,
    RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
  if (resultMap.hasNestedResultMaps()) {
    ensureNoRowBounds();
    checkResultHandler();
    handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
  } else {
    handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
  }
}
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); 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++; } } return collapseSingleResultList(multipleResults); } private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException { try { if (parentMapping != null) { handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping); } else if (resultHandler == null) { DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory); handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null); multipleResults.add(defaultResultHandler.getResultList()); } else { handleRowValues(rsw, resultMap, resultHandler, rowBounds, null); } } finally { closeResultSet(rsw.getResultSet()); } } public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { if (resultMap.hasNestedResultMaps()) { ensureNoRowBounds(); checkResultHandler(); handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } else { handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } }

结果集封装主要有两个步骤:

  1. 根据ResultMap初始化响应Java对象
  2. 根据的属性-列字段名映射关系,从结果集获取对应值,设置到响应对象中
  3. 将该行结果集封装的Java对象,添加到返回值列表中

DefaultResultSetHandler#handleRowValuesForSimpleResultMap、DefaultResultSetHandler#getRowValue和DefaultResultSetHandler#applyAutomaticMappings:

private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
ResultSet resultSet = rsw.getResultSet();
skipRows(resultSet, rowBounds);
while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
// 获取每一行的响应对象
Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
// 添加返回值列表
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if (shouldApplyAutomaticMappings(resultMap, false)) {
// 自动映射
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
String columnPrefix) throws SQLException {
List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
boolean foundValues = false;
if (!autoMapping.isEmpty()) {
// 遍历属性-列字段名映射
for (UnMappedColumnAutoMapping mapping : autoMapping) {
// 将列数据封装成对应Java类型的属性值
final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
if (value != null) {
foundValues = true;
}
if (value != null || configuration.isCallSettersOnNulls() && !mapping.primitive) {
// 将属性值设置到响应对象的成员变量中
metaObject.setValue(mapping.property, value);
}
}
}
return foundValues;
}
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
    ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
  DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
  ResultSet resultSet = rsw.getResultSet();
  skipRows(resultSet, rowBounds);
  while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
    ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
    // 获取每一行的响应对象
    Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
    // 添加返回值列表
    storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
  }
}

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
  final ResultLoaderMap lazyLoader = new ResultLoaderMap();
  Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
  if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
    final MetaObject metaObject = configuration.newMetaObject(rowValue);
    boolean foundValues = this.useConstructorMappings;
    if (shouldApplyAutomaticMappings(resultMap, false)) {
      // 自动映射
      foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
    }
    foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
    foundValues = lazyLoader.size() > 0 || foundValues;
    rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
  }
  return rowValue;
}

private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
    String columnPrefix) throws SQLException {
  List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
  boolean foundValues = false;
  if (!autoMapping.isEmpty()) {
    // 遍历属性-列字段名映射
    for (UnMappedColumnAutoMapping mapping : autoMapping) {
      // 将列数据封装成对应Java类型的属性值
      final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
      if (value != null) {
        foundValues = true;
      }
      if (value != null || configuration.isCallSettersOnNulls() && !mapping.primitive) {
        // 将属性值设置到响应对象的成员变量中
        metaObject.setValue(mapping.property, value);
      }
    }
  }
  return foundValues;
}
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { DefaultResultContext<Object> resultContext = new DefaultResultContext<>(); ResultSet resultSet = rsw.getResultSet(); skipRows(resultSet, rowBounds); while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) { ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null); // 获取每一行的响应对象 Object rowValue = getRowValue(rsw, discriminatedResultMap, null); // 添加返回值列表 storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet); } } private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException { final ResultLoaderMap lazyLoader = new ResultLoaderMap(); Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix); if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { final MetaObject metaObject = configuration.newMetaObject(rowValue); boolean foundValues = this.useConstructorMappings; if (shouldApplyAutomaticMappings(resultMap, false)) { // 自动映射 foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues; } foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues; foundValues = lazyLoader.size() > 0 || foundValues; rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null; } return rowValue; } private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException { List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix); boolean foundValues = false; if (!autoMapping.isEmpty()) { // 遍历属性-列字段名映射 for (UnMappedColumnAutoMapping mapping : autoMapping) { // 将列数据封装成对应Java类型的属性值 final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column); if (value != null) { foundValues = true; } if (value != null || configuration.isCallSettersOnNulls() && !mapping.primitive) { // 将属性值设置到响应对象的成员变量中 metaObject.setValue(mapping.property, value); } } } return foundValues; }

2.1.2 Executor#update#

除了自定义Interceptor,首先会进入到CachingExecutor#update方法,它主要对全局缓存进行清除工作,然后再调用代理对象的BaseExecutor#update方法。

CachingExecutor#update和CachingExecutor#flushCacheIfRequired:

public int update(MappedStatement ms, Object parameterObject) throws SQLException {
// 清除全局缓存
flushCacheIfRequired(ms);
// 执行代理对象更新方法
return delegate.update(ms, parameterObject);
}
private void flushCacheIfRequired(MappedStatement ms) {
// 从MappedStatement中获取缓存
Cache cache = ms.getCache();
if (cache != null && ms.isFlushCacheRequired()) {
// 清除缓存
tcm.clear(cache);
}
}
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
  // 清除全局缓存
  flushCacheIfRequired(ms);
  // 执行代理对象更新方法
  return delegate.update(ms, parameterObject);
}

private void flushCacheIfRequired(MappedStatement ms) {
  // 从MappedStatement中获取缓存
  Cache cache = ms.getCache();
  if (cache != null && ms.isFlushCacheRequired()) {
    // 清除缓存
    tcm.clear(cache);
  }
}
public int update(MappedStatement ms, Object parameterObject) throws SQLException { // 清除全局缓存 flushCacheIfRequired(ms); // 执行代理对象更新方法 return delegate.update(ms, parameterObject); } private void flushCacheIfRequired(MappedStatement ms) { // 从MappedStatement中获取缓存 Cache cache = ms.getCache(); if (cache != null && ms.isFlushCacheRequired()) { // 清除缓存 tcm.clear(cache); } }

BaseExecutor#update会对局部缓存进行清除,然后调用实现类的doUpdate方法。

BaseExecutor#update和BaseExecutor#clearLocalCache:

public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 清除局部缓存
clearLocalCache();
// 执行实现类更新方法
return doUpdate(ms, parameter);
}
public void clearLocalCache() {
if (!closed) {
localCache.clear();
localOutputParameterCache.clear();
}
}
public int update(MappedStatement ms, Object parameter) throws SQLException {
  ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
  if (closed) {
    throw new ExecutorException("Executor was closed.");
  }
  // 清除局部缓存
  clearLocalCache();
  // 执行实现类更新方法
  return doUpdate(ms, parameter);
}

public void clearLocalCache() {
  if (!closed) {
    localCache.clear();
    localOutputParameterCache.clear();
  }
}
public int update(MappedStatement ms, Object parameter) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } // 清除局部缓存 clearLocalCache(); // 执行实现类更新方法 return doUpdate(ms, parameter); } public void clearLocalCache() { if (!closed) { localCache.clear(); localOutputParameterCache.clear(); } }

默认执行器实现类为SimpleExecutor,与doQuery方法类似,其doUpdate方法会执行如下逻辑:

  1. 创建StatementHandler
  2. 创建Statement(参数解析)
  3. 执行Statement
  4. 结果集封装

SimpleExecutor#doUpdate:

public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
// 创建StatementHandler
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
// 创建Statement(参数解析)
stmt = prepareStatement(handler, ms.getStatementLog());
// 执行Statement&结果集封装
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
  Statement stmt = null;
  try {
    Configuration configuration = ms.getConfiguration();
    // 创建StatementHandler
    StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
    // 创建Statement(参数解析)
    stmt = prepareStatement(handler, ms.getStatementLog());
    // 执行Statement&结果集封装
    return handler.update(stmt);
  } finally {
    closeStatement(stmt);
  }
}
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); // 创建StatementHandler StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); // 创建Statement(参数解析) stmt = prepareStatement(handler, ms.getStatementLog()); // 执行Statement&结果集封装 return handler.update(stmt); } finally { closeStatement(stmt); } }

前2个步骤与doQuery方法相同,这里不再赘述,主要看后两个步骤,对应为StatementHandler#update方法,默认实现类为PreparedStatementHandler。

由于数据库insert/update/delete操作返回的都是影响条数,同查询相比,它们的结果集封装就显得十分简单:直接返回即可。

相反,由于数据库insert操作会新增主键,为了将主键值回显给入参对象,这里还需要进行特殊处理。

public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 执行SQL
ps.execute();
// 获取影响条数
int rows = ps.getUpdateCount();
// 回显主键值
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}
public int update(Statement statement) throws SQLException {
  PreparedStatement ps = (PreparedStatement) statement;
  // 执行SQL
  ps.execute();
  // 获取影响条数
  int rows = ps.getUpdateCount();
  // 回显主键值
  Object parameterObject = boundSql.getParameterObject();
  KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
  keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
  return rows;
}
public int update(Statement statement) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; // 执行SQL ps.execute(); // 获取影响条数 int rows = ps.getUpdateCount(); // 回显主键值 Object parameterObject = boundSql.getParameterObject(); KeyGenerator keyGenerator = mappedStatement.getKeyGenerator(); keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject); return rows; }

如果没有设置回显主键(默认情况下),KeyGenerator实现类为NoKeyGenerator,其processAfter是个空方法:

public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
// Do Nothing
}
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
  // Do Nothing
}
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) { // Do Nothing }

通过以下方式可以开启回显主键功能:

<insert id="createUser" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
<!-- SQL -->
</insert>
<insert id="createUser" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
  <!-- SQL -->
</insert>
<insert id="createUser" useGeneratedKeys="true" keyColumn="id" keyProperty="id"> <!-- SQL --> </insert>

此时默认KeyGenerator实现类为Jdbc3KeyGenerator,它会从结果集中获取对应数据库主键值(keyColumn),设置到入参对象的对应属性(keyProperty):

public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
processBatch(ms, stmt, parameter);
}
public void processBatch(MappedStatement ms, Statement stmt, Object parameter) {
final String[] keyProperties = ms.getKeyProperties();
if (keyProperties == null || keyProperties.length == 0) {
return;
}
// 遍历结果集
try (ResultSet rs = stmt.getGeneratedKeys()) {
final ResultSetMetaData rsmd = rs.getMetaData();
final Configuration configuration = ms.getConfiguration();
if (rsmd.getColumnCount() < keyProperties.length) {
// Error?
} else {
// 回显主键
assignKeys(configuration, rs, rsmd, keyProperties, parameter);
}
} catch (Exception e) {
throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e);
}
}
private void assignKeys(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd, String[] keyProperties,
Object parameter) throws SQLException {
if (parameter instanceof ParamMap || parameter instanceof StrictMap) {
// Multi-param or single param with @Param
assignKeysToParamMap(configuration, rs, rsmd, keyProperties, (Map<String, ?>) parameter);
} else if (parameter instanceof ArrayList && !((ArrayList<?>) parameter).isEmpty()
&& ((ArrayList<?>) parameter).get(0) instanceof ParamMap) {
// Multi-param or single param with @Param in batch operation
assignKeysToParamMapList(configuration, rs, rsmd, keyProperties, (ArrayList<ParamMap<?>>) parameter);
} else {
// Single param without @Param
assignKeysToParam(configuration, rs, rsmd, keyProperties, parameter);
}
}
private void assignKeysToParam(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
String[] keyProperties, Object parameter) throws SQLException {
Collection<?> params = collectionize(parameter);
if (params.isEmpty()) {
return;
}
List<KeyAssigner> assignerList = new ArrayList<>();
for (int i = 0; i < keyProperties.length; i++) {
assignerList.add(new KeyAssigner(configuration, rsmd, i + 1, null, keyProperties[i]));
}
Iterator<?> iterator = params.iterator();
while (rs.next()) {
if (!iterator.hasNext()) {
throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, params.size()));
}
Object param = iterator.next();
// 设值
assignerList.forEach(x -> x.assign(rs, param));
}
}
protected void assign(ResultSet rs, Object param) {
if (paramName != null) {
// If paramName is set, param is ParamMap
param = ((ParamMap<?>) param).get(paramName);
}
MetaObject metaParam = configuration.newMetaObject(param);
try {
if (typeHandler == null) {
if (!metaParam.hasSetter(propertyName)) {
throw new ExecutorException("No setter found for the keyProperty '" + propertyName + "' in '"
+ metaParam.getOriginalObject().getClass().getName() + "'.");
}
Class<?> propertyType = metaParam.getSetterType(propertyName);
typeHandler = typeHandlerRegistry.getTypeHandler(propertyType,
JdbcType.forCode(rsmd.getColumnType(columnPosition)));
}
if (typeHandler == null) {
// Error?
} else {
// 获取数据库主键值
Object value = typeHandler.getResult(rs, columnPosition);
// 设置入参
metaParam.setValue(propertyName, value);
}
} catch (SQLException e) {
throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e,
e);
}
}
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
  processBatch(ms, stmt, parameter);
}

public void processBatch(MappedStatement ms, Statement stmt, Object parameter) {
  final String[] keyProperties = ms.getKeyProperties();
  if (keyProperties == null || keyProperties.length == 0) {
    return;
  }
  // 遍历结果集
  try (ResultSet rs = stmt.getGeneratedKeys()) {
    final ResultSetMetaData rsmd = rs.getMetaData();
    final Configuration configuration = ms.getConfiguration();
    if (rsmd.getColumnCount() < keyProperties.length) {
      // Error?
    } else {
      // 回显主键
      assignKeys(configuration, rs, rsmd, keyProperties, parameter);
    }
  } catch (Exception e) {
    throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e);
  }
}

private void assignKeys(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd, String[] keyProperties,
    Object parameter) throws SQLException {
  if (parameter instanceof ParamMap || parameter instanceof StrictMap) {
    // Multi-param or single param with @Param
    assignKeysToParamMap(configuration, rs, rsmd, keyProperties, (Map<String, ?>) parameter);
  } else if (parameter instanceof ArrayList && !((ArrayList<?>) parameter).isEmpty()
      && ((ArrayList<?>) parameter).get(0) instanceof ParamMap) {
    // Multi-param or single param with @Param in batch operation
    assignKeysToParamMapList(configuration, rs, rsmd, keyProperties, (ArrayList<ParamMap<?>>) parameter);
  } else {
    // Single param without @Param
    assignKeysToParam(configuration, rs, rsmd, keyProperties, parameter);
  }
}

private void assignKeysToParam(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
    String[] keyProperties, Object parameter) throws SQLException {
  Collection<?> params = collectionize(parameter);
  if (params.isEmpty()) {
    return;
  }
  List<KeyAssigner> assignerList = new ArrayList<>();
  for (int i = 0; i < keyProperties.length; i++) {
    assignerList.add(new KeyAssigner(configuration, rsmd, i + 1, null, keyProperties[i]));
  }
  Iterator<?> iterator = params.iterator();
  while (rs.next()) {
    if (!iterator.hasNext()) {
      throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, params.size()));
    }
    Object param = iterator.next();
    // 设值
    assignerList.forEach(x -> x.assign(rs, param));
  }
}

protected void assign(ResultSet rs, Object param) {
    if (paramName != null) {
      // If paramName is set, param is ParamMap
      param = ((ParamMap<?>) param).get(paramName);
    }
    MetaObject metaParam = configuration.newMetaObject(param);
    try {
      if (typeHandler == null) {
        if (!metaParam.hasSetter(propertyName)) {
          throw new ExecutorException("No setter found for the keyProperty '" + propertyName + "' in '"
              + metaParam.getOriginalObject().getClass().getName() + "'.");
        }
        Class<?> propertyType = metaParam.getSetterType(propertyName);
        typeHandler = typeHandlerRegistry.getTypeHandler(propertyType,
            JdbcType.forCode(rsmd.getColumnType(columnPosition)));
      }
      if (typeHandler == null) {
        // Error?
      } else {
        // 获取数据库主键值
        Object value = typeHandler.getResult(rs, columnPosition);
        // 设置入参
        metaParam.setValue(propertyName, value);
      }
    } catch (SQLException e) {
      throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e,
          e);
    }
  }
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) { processBatch(ms, stmt, parameter); } public void processBatch(MappedStatement ms, Statement stmt, Object parameter) { final String[] keyProperties = ms.getKeyProperties(); if (keyProperties == null || keyProperties.length == 0) { return; } // 遍历结果集 try (ResultSet rs = stmt.getGeneratedKeys()) { final ResultSetMetaData rsmd = rs.getMetaData(); final Configuration configuration = ms.getConfiguration(); if (rsmd.getColumnCount() < keyProperties.length) { // Error? } else { // 回显主键 assignKeys(configuration, rs, rsmd, keyProperties, parameter); } } catch (Exception e) { throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e); } } private void assignKeys(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd, String[] keyProperties, Object parameter) throws SQLException { if (parameter instanceof ParamMap || parameter instanceof StrictMap) { // Multi-param or single param with @Param assignKeysToParamMap(configuration, rs, rsmd, keyProperties, (Map<String, ?>) parameter); } else if (parameter instanceof ArrayList && !((ArrayList<?>) parameter).isEmpty() && ((ArrayList<?>) parameter).get(0) instanceof ParamMap) { // Multi-param or single param with @Param in batch operation assignKeysToParamMapList(configuration, rs, rsmd, keyProperties, (ArrayList<ParamMap<?>>) parameter); } else { // Single param without @Param assignKeysToParam(configuration, rs, rsmd, keyProperties, parameter); } } private void assignKeysToParam(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd, String[] keyProperties, Object parameter) throws SQLException { Collection<?> params = collectionize(parameter); if (params.isEmpty()) { return; } List<KeyAssigner> assignerList = new ArrayList<>(); for (int i = 0; i < keyProperties.length; i++) { assignerList.add(new KeyAssigner(configuration, rsmd, i + 1, null, keyProperties[i])); } Iterator<?> iterator = params.iterator(); while (rs.next()) { if (!iterator.hasNext()) { throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, params.size())); } Object param = iterator.next(); // 设值 assignerList.forEach(x -> x.assign(rs, param)); } } protected void assign(ResultSet rs, Object param) { if (paramName != null) { // If paramName is set, param is ParamMap param = ((ParamMap<?>) param).get(paramName); } MetaObject metaParam = configuration.newMetaObject(param); try { if (typeHandler == null) { if (!metaParam.hasSetter(propertyName)) { throw new ExecutorException("No setter found for the keyProperty '" + propertyName + "' in '" + metaParam.getOriginalObject().getClass().getName() + "'."); } Class<?> propertyType = metaParam.getSetterType(propertyName); typeHandler = typeHandlerRegistry.getTypeHandler(propertyType, JdbcType.forCode(rsmd.getColumnType(columnPosition))); } if (typeHandler == null) { // Error? } else { // 获取数据库主键值 Object value = typeHandler.getResult(rs, columnPosition); // 设置入参 metaParam.setValue(propertyName, value); } } catch (SQLException e) { throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e); } }

2.2 使用映射接口代理对象执行#

通过SqlSession#getMapper方法,可以获取映射接口的代理对象。

该代理对象实际上是从Configuration中获取的,Configuration又是从MapperRegistry中获取的,MapperRegistry会从缓存中获取MapperProxyFactory创建SqlSession的代理对象。

DefaultSqlSession#getMapper、Configuration#getMapper、MapperRegistry#getMapper和MapperProxyFactory#newInstance:

// DefaultSqlSession
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
// Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
// MapperRegistry
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 获取缓存对应的MapperProxyFactory
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);
}
}
// MapperProxyFactory
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
// DefaultSqlSession
public <T> T getMapper(Class<T> type) {
  return configuration.getMapper(type, this);
}

// Configuration
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  return mapperRegistry.getMapper(type, sqlSession);
}

// MapperRegistry
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  // 获取缓存对应的MapperProxyFactory
  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);
  }
}

// MapperProxyFactory
public T newInstance(SqlSession sqlSession) {
  final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
  return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
  return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
// DefaultSqlSession public <T> T getMapper(Class<T> type) { return configuration.getMapper(type, this); } // Configuration public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); } // MapperRegistry public <T> T getMapper(Class<T> type, SqlSession sqlSession) { // 获取缓存对应的MapperProxyFactory 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); } } // MapperProxyFactory public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } protected T newInstance(MapperProxy<T> mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); }

MapperProxyFactory使用JDK的Proxy创建代理对象,实际逻辑位于InvocationHandler实现类MapperProxy的invoke方法中,它会创建MapperMethodInvoker对象(PlainMethodInvoker)并执行其invoke方法:

// MapperProxy
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
try {
return MapUtil.computeIfAbsent(methodCache, method, m -> {
if (!m.isDefault()) {
// 对于映射接口方法,会创建此对象
return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
try {
if (privateLookupInMethod == null) {
return new DefaultMethodInvoker(getMethodHandleJava8(method));
} else {
return new DefaultMethodInvoker(getMethodHandleJava9(method));
}
} catch (IllegalAccessException | InstantiationException | InvocationTargetException
| NoSuchMethodException e) {
throw new RuntimeException(e);
}
});
} catch (RuntimeException re) {
Throwable cause = re.getCause();
throw cause == null ? re : cause;
}
}
// PlainMethodInvoker
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
return mapperMethod.execute(sqlSession, args);
}
// MapperProxy
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  try {
    if (Object.class.equals(method.getDeclaringClass())) {
      return method.invoke(this, args);
    }
    return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
  } catch (Throwable t) {
    throw ExceptionUtil.unwrapThrowable(t);
  }
}
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
  try {
    return MapUtil.computeIfAbsent(methodCache, method, m -> {
      if (!m.isDefault()) {
        // 对于映射接口方法,会创建此对象
        return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
      }
      try {
        if (privateLookupInMethod == null) {
          return new DefaultMethodInvoker(getMethodHandleJava8(method));
        } else {
          return new DefaultMethodInvoker(getMethodHandleJava9(method));
        }
      } catch (IllegalAccessException | InstantiationException | InvocationTargetException
          | NoSuchMethodException e) {
        throw new RuntimeException(e);
      }
    });
  } catch (RuntimeException re) {
    Throwable cause = re.getCause();
    throw cause == null ? re : cause;
  }
}

// PlainMethodInvoker
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
  return mapperMethod.execute(sqlSession, args);
}
// MapperProxy public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } return cachedInvoker(method).invoke(proxy, method, args, sqlSession); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } private MapperMethodInvoker cachedInvoker(Method method) throws Throwable { try { return MapUtil.computeIfAbsent(methodCache, method, m -> { if (!m.isDefault()) { // 对于映射接口方法,会创建此对象 return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration())); } try { if (privateLookupInMethod == null) { return new DefaultMethodInvoker(getMethodHandleJava8(method)); } else { return new DefaultMethodInvoker(getMethodHandleJava9(method)); } } catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) { throw new RuntimeException(e); } }); } catch (RuntimeException re) { Throwable cause = re.getCause(); throw cause == null ? re : cause; } } // PlainMethodInvoker public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable { return mapperMethod.execute(sqlSession, args); }

PlainMethodInvoker#invoke又会执行MapperMethod#execute方法,从该方法中可以明显看到,映射接口代理对象只不过是对SqlSession对象进行的封装,实际操作数据库还是得依靠SqlSession(此时又回到了2.1根据statementId执行的流程):

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;
}
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;
}
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; }

还有个问题,MapperProxyFactory是什么时候生成的?实际上,在Mybatis启动时,通过MapperRegistry#addMapper方法就会创建MapperProxyFactory缓存(具体流程可以查看Mybatis如何添加映射接口和映射文件?):

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 {
// 添加MapperProxyFactory缓存
knownMappers.put(type, new MapperProxyFactory<>(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);
}
}
}
}
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 {
      // 添加MapperProxyFactory缓存
      knownMappers.put(type, new MapperProxyFactory<>(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);
      }
    }
  }
}
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 { // 添加MapperProxyFactory缓存 knownMappers.put(type, new MapperProxyFactory<>(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); } } } }

我们也可以发现,MapperProxyFactory缓存与MappedStatement并没有直接关系,它们之间需要SqlSession进行连接。即映射接口代理对象 -> SqlSession -> Configuration -> MapperRegistry -> 映射文件。

3 关闭SqlSession#

数据库连接是计算机网络资源,使用完需要及时关闭,避免资源泄露,造成服务器性能下降。

如果使用了数据库连接池,则需要清理本次会话的缓存数据,将连接放回连接池。

使用SqlSession#close()可以关闭本次会话连接,由于SqlSession实现了Closeable接口,通常使用以下方式自动关闭:

try (SqlSession session = sqlSessionFactory.openSession(true)) {
// 执行SQL语句
}
try (SqlSession session = sqlSessionFactory.openSession(true)) {
  // 执行SQL语句
}
try (SqlSession session = sqlSessionFactory.openSession(true)) { // 执行SQL语句 }

SqlSession#close()方法会本次会话的执行器Executor和游标Cursor,具体怎么关闭资源,实际上是由执行器和游标实现类自己去实现的。总体来说会完成一下工作:

  1. 清除会话缓存数据。
  2. 关闭数据库连接。如果使用连接池,则会本次连接放回连接池。

以下为相关源码。

SqlSession#close()关闭executor和cursor:

public void close() {
try {
executor.close(isCommitOrRollbackRequired(false));
closeCursors();
dirty = false;
} finally {
ErrorContext.instance().reset();
}
}
public void close() {
  try {
    executor.close(isCommitOrRollbackRequired(false));
    closeCursors();
    dirty = false;
  } finally {
    ErrorContext.instance().reset();
  }
}
public void close() { try { executor.close(isCommitOrRollbackRequired(false)); closeCursors(); dirty = false; } finally { ErrorContext.instance().reset(); } }

CachingExecutor#close()会回滚/提交本次会话的缓存,然后关闭代理执行器资源:

public void close(boolean forceRollback) {
try {
// issues #499, #524 and #573
if (forceRollback) {
tcm.rollback();
} else {
tcm.commit();
}
} finally {
delegate.close(forceRollback);
}
}
public void close(boolean forceRollback) {
  try {
    // issues #499, #524 and #573
    if (forceRollback) {
      tcm.rollback();
    } else {
      tcm.commit();
    }
  } finally {
    delegate.close(forceRollback);
  }
}
public void close(boolean forceRollback) { try { // issues #499, #524 and #573 if (forceRollback) { tcm.rollback(); } else { tcm.commit(); } } finally { delegate.close(forceRollback); } }

BaseExecutor#close()会关闭事务,并清除本地缓存:

public void close(boolean forceRollback) {
try {
try {
rollback(forceRollback);
} finally {
if (transaction != null) {
transaction.close();
}
}
} catch (SQLException e) {
// Ignore. There's nothing that can be done at this point.
log.warn("Unexpected exception on closing transaction. Cause: " + e);
} finally {
transaction = null;
deferredLoads = null;
localCache = null;
localOutputParameterCache = null;
closed = true;
}
}
public void close(boolean forceRollback) {
  try {
    try {
      rollback(forceRollback);
    } finally {
      if (transaction != null) {
        transaction.close();
      }
    }
  } catch (SQLException e) {
    // Ignore. There's nothing that can be done at this point.
    log.warn("Unexpected exception on closing transaction.  Cause: " + e);
  } finally {
    transaction = null;
    deferredLoads = null;
    localCache = null;
    localOutputParameterCache = null;
    closed = true;
  }
}
public void close(boolean forceRollback) { try { try { rollback(forceRollback); } finally { if (transaction != null) { transaction.close(); } } } catch (SQLException e) { // Ignore. There's nothing that can be done at this point. log.warn("Unexpected exception on closing transaction. Cause: " + e); } finally { transaction = null; deferredLoads = null; localCache = null; localOutputParameterCache = null; closed = true; } }

Transaction#close()会关闭数据库连接,具体怎么实现交给子类决定。

例如,JdbcTransaction#Close()会直接关闭connection:

public void close() throws SQLException {
if (connection != null) {
resetAutoCommit();
if (log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + connection + "]");
}
connection.close();
}
}
public void close() throws SQLException {
  if (connection != null) {
    resetAutoCommit();
    if (log.isDebugEnabled()) {
      log.debug("Closing JDBC Connection [" + connection + "]");
    }
    connection.close();
  }
}
public void close() throws SQLException { if (connection != null) { resetAutoCommit(); if (log.isDebugEnabled()) { log.debug("Closing JDBC Connection [" + connection + "]"); } connection.close(); } }

SqlSession#closeCursors()遍历关闭所有corsor:

private void closeCursors() {
if (cursorList != null && !cursorList.isEmpty()) {
for (Cursor<?> cursor : cursorList) {
try {
cursor.close();
} catch (IOException e) {
throw ExceptionFactory.wrapException("Error closing cursor. Cause: " + e, e);
}
}
cursorList.clear();
}
}
private void closeCursors() {
  if (cursorList != null && !cursorList.isEmpty()) {
    for (Cursor<?> cursor : cursorList) {
      try {
        cursor.close();
      } catch (IOException e) {
        throw ExceptionFactory.wrapException("Error closing cursor.  Cause: " + e, e);
      }
    }
    cursorList.clear();
  }
}
private void closeCursors() { if (cursorList != null && !cursorList.isEmpty()) { for (Cursor<?> cursor : cursorList) { try { cursor.close(); } catch (IOException e) { throw ExceptionFactory.wrapException("Error closing cursor. Cause: " + e, e); } } cursorList.clear(); } }

DefaultCursor#close()关闭结果集ResultSet:

public void close() {
if (isClosed()) {
return;
}
ResultSet rs = rsw.getResultSet();
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
// ignore
} finally {
status = CursorStatus.CLOSED;
}
}
public void close() {
  if (isClosed()) {
    return;
  }
  ResultSet rs = rsw.getResultSet();
  try {
    if (rs != null) {
      rs.close();
    }
  } catch (SQLException e) {
    // ignore
  } finally {
    status = CursorStatus.CLOSED;
  }
}
public void close() { if (isClosed()) { return; } ResultSet rs = rsw.getResultSet(); try { if (rs != null) { rs.close(); } } catch (SQLException e) { // ignore } finally { status = CursorStatus.CLOSED; } }

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYNfFGJp' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片