0%

mybatis详细执行过程

MyBatis 详细执行过程:从源码视角拆解核心流程

MyBatis 的执行过程本质是 “配置解析→核心对象创建→SQL 执行→结果封装” 的闭环,涉及 ConfigurationSqlSessionExecutorStatementHandler 等核心组件的协同工作。本文结合 MyBatis 3.5.x 源码,将执行过程拆解为 7 个关键步骤,每个步骤深入核心源码与组件职责,帮你彻底理解 MyBatis 的运行机制。

核心执行流程总览

MyBatis 从初始化到执行 SQL 的完整流程可概括为:
配置加载 → 创建 SqlSessionFactory → 创建 SqlSession → 获取 Mapper 代理 → 执行 SQL(Executor 调度) → 数据库交互(StatementHandler) → 结果封装(ResultSetHandler)

先通过一张简化的组件协作图理解核心关系:

详细执行步骤(结合源码)

步骤 1:加载配置文件,初始化 Configuration 对象

MyBatis 启动时,首先解析 全局配置文件(mybatis-config.xml)所有 Mapper 映射文件(XxxMapper.xml),将配置信息统一封装到 Configuration 对象中(Configuration 是 MyBatis 的 “配置中心”,全局唯一)。

核心源码:SqlSessionFactoryBuilder.build()

SqlSessionFactoryBuilder 是创建 SqlSessionFactory 的入口,其核心逻辑是解析配置文件生成 Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// org.mybatis.session.SqlSessionFactoryBuilder
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 1. 创建 XML 配置解析器,解析 mybatis-config.xml
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// 2. 解析配置文件,生成 Configuration 对象,再创建 SqlSessionFactory
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Ignore
}
}
}

// 最终创建 DefaultSqlSessionFactory(SqlSessionFactory 的默认实现)
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
关键解析逻辑(XMLConfigBuilder.parse()

XMLConfigBuilder 会逐节点解析 mybatis-config.xml,核心包括:

  • 数据库环境(environments):解析数据源(DataSource)和事务管理器(TransactionManager),存入 Configuration.environments
  • Mapper 映射(mappers):解析所有 Mapper.xml,将 SQL 语句、结果映射(ResultMap)等存入 Configuration.mappedStatementsMappedStatement 封装单条 SQL 的完整信息);
  • 全局设置(settings):如 cacheEnabled(二级缓存开关)、mapUnderscoreToCamelCase(驼峰映射),存入 Configuration 对应属性;
  • 类型别名(typeAliases):解析别名映射,存入 Configuration.typeAliasRegistry
小结:

此步骤的核心是 “将 XML 配置转化为内存中的 Configuration 对象”,后续所有核心组件的创建都依赖该对象。

步骤 2:创建 SqlSession(数据库会话)

SqlSession 相当于 JDBC 的 Connection,代表一次数据库会话,通过 SqlSessionFactory.openSession() 创建,生命周期为单次业务请求(线程不安全,需及时关闭)。

核心源码:DefaultSqlSessionFactory.openSession()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// org.mybatis.session.defaults.DefaultSqlSessionFactory
@Override
public SqlSession openSession() {
// 默认不自动提交事务,使用全局配置的 Executor 类型
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 1. 获取配置的数据库环境(environment)
final Environment environment = configuration.getEnvironment();
// 2. 创建事务管理器(Transaction)
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 3. 创建 Executor(执行器,MyBatis 核心执行组件)
final Executor executor = configuration.newExecutor(tx, execType);
// 4. 创建 DefaultSqlSession(SqlSession 的默认实现)
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();
}
}
关键组件:Executor(执行器)

Executor 是 MyBatis 的 “执行引擎”,负责 SQL 执行的调度(如缓存查询、事务管理、SQL 语句执行),根据 execType 生成不同类型:

  • SIMPLE:默认执行器,每次执行 SQL 都创建新的 Statement
  • REUSE:复用 Statement(缓存 Statement 对象);
  • BATCH:批量执行器,适合批量插入 / 更新;
  • CACHING:若开启二级缓存(cacheEnabled=true),会用 CachingExecutor 装饰上述执行器,添加缓存逻辑。
小结:

此步骤的核心是 “创建 SqlSession 及其依赖的 Executor 和 Transaction”,SqlSession 持有 Configuration 和 Executor,是后续操作的入口。

步骤 3:获取 Mapper 接口的动态代理对象

MyBatis 不直接实现 Mapper 接口,而是通过 JDK 动态代理 生成 MapperProxy 对象,将 Mapper 方法调用委托给 SqlSession 执行。

核心源码:DefaultSqlSession.getMapper()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// org.mybatis.session.defaults.DefaultSqlSession
@Override
public <T> T getMapper(Class<T> type) {
// 委托给 Configuration 的 MapperRegistry 获取 Mapper 代理
return configuration.getMapper(type, this);
}

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

// org.apache.ibatis.binding.MapperRegistry
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 1. 获取 Mapper 代理工厂(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 {
// 2. 生成 Mapper 代理对象(MapperProxy)
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
动态代理核心:MapperProxy

MapperProxy 实现 InvocationHandler 接口,是 JDK 动态代理的 “调用处理器”,所有 Mapper 方法调用都会触发 invoke 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// org.apache.ibatis.binding.MapperProxy
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 1. 过滤 Object 类的方法(如 toString、hashCode)
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
// 2. 将方法调用委托给 MapperMethod 执行
return cachedMapperMethod(method).execute(sqlSession, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
小结:

此步骤的核心是 “通过 JDK 动态代理生成 MapperProxy,将 Mapper 方法调用转发给 SqlSession”,避免手动实现 Mapper 接口。

步骤 4:解析 Mapper 方法,生成 MappedStatementBoundSql

当调用 Mapper 方法(如 userMapper.selectById(1))时,MyBatis 会先解析该方法对应的 MappedStatement(封装 SQL 元信息)和 BoundSql(封装解析后的 SQL 和参数)。

核心源码:MapperMethod.execute()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// org.apache.ibatis.binding.MapperMethod
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
// 根据 SQL 命令类型(SELECT/INSERT/UPDATE/DELETE)执行对应逻辑
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 {
// 单结果查询(如 selectById)
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
break;
// 其他类型(如 FLUSH)省略...
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
return result;
}
关键对象:MappedStatementBoundSql
  • MappedStatement:从 Configuration.mappedStatements 中获取,key 为 namespace + methodName(如 com.xxx.mapper.UserMapper.selectById),封装了 SQL 语句、参数类型、结果类型、缓存配置等元信息;
  • BoundSql:由 MappedStatement.getBoundSql(param) 生成,封装了解析后的 SQL 语句(如动态 SQL 拼接后的结果)、参数映射列表(parameterMappings)、参数值(parameterObject)。
小结:

此步骤的核心是 “根据 Mapper 方法找到对应的 MappedStatement,生成包含最终 SQL 和参数的 BoundSql”,为后续 SQL 执行做准备。

步骤 5:Executor 调度执行,创建核心处理组件

SqlSession 的增删改查方法最终会委托给 Executor 执行,Executor 会创建 StatementHandlerParameterHandlerResultSetHandler 三个核心组件,分别负责 SQL 执行、参数设置、结果封装

selectOne 为例,核心源码追踪:

  1. DefaultSqlSession.selectOne() → 调用 selectList() 取第一个结果;
  2. DefaultSqlSession.selectList() → 委托 Executor.query()
  3. Executor.query() → 若开启二级缓存,CachingExecutor 先查缓存,未命中则调用 delegate(如 SimpleExecutor)的 query()
  4. SimpleExecutor.query() → 调用 doQuery()(实际执行逻辑)。
核心源码:SimpleExecutor.doQuery()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// org.apache.ibatis.executor.SimpleExecutor
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
// 1. 获取 Configuration 对象
Configuration configuration = ms.getConfiguration();
// 2. 创建 StatementHandler(SQL 执行处理器,核心组件)
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 3. 创建并配置 Statement(JDBC 的 Statement/PreparedStatement)
stmt = prepareStatement(handler, ms.getStatementLog());
// 4. 执行查询,通过 ResultSetHandler 封装结果
return handler.query(stmt, resultHandler);
} finally {
// 5. 关闭 Statement
closeStatement(stmt);
}
}

// 准备 Statement:预编译 SQL + 设置参数
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 获取数据库连接(从 Transaction 中获取)
Connection connection = getConnection(statementLog);
// 1. 预编译 SQL:创建 PreparedStatement,调用 StatementHandler.prepare()
stmt = handler.prepare(connection, transaction.getTimeout());
// 2. 设置参数:调用 StatementHandler.parameterize(),内部使用 ParameterHandler
handler.parameterize(stmt);
return stmt;
}
核心组件职责分工:
组件 核心职责 默认实现类
StatementHandler 管理 JDBC Statement,负责 SQL 预编译、执行 RoutingStatementHandler
ParameterHandler 为预编译 SQL 设置参数(处理 ? 占位符) DefaultParameterHandler
ResultSetHandler 解析 ResultSet,封装为实体类 DefaultResultSetHandler
小结:

此步骤的核心是 “Executor 调度创建三大组件,完成 SQL 预编译和参数设置”,是 MyBatis 与 JDBC 交互的核心环节。

步骤 6:StatementHandler 执行 SQL,与数据库交互

StatementHandler 是 MyBatis 与数据库交互的 “直接执行者”,负责创建 Statement、预编译 SQL、执行 SQL 并返回 ResultSet

核心源码:PreparedStatementHandler(常用实现)

RoutingStatementHandler 会根据 MappedStatementstatementType(默认 PREPARED)选择具体的 StatementHandler 实现,以 PreparedStatementHandler 为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// org.apache.ibatis.executor.statement.PreparedStatementHandler
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
PreparedStatement stmt = null;
try {
// 1. 创建 PreparedStatement(预编译 SQL)
stmt = connection.prepareStatement(boundSql.getSql(), ms.getStatementType() == StatementType.CALLABLE ? ResultSet.TYPE_SCROLL_INSENSITIVE : ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
// 2. 设置超时时间
setStatementTimeout(stmt, transactionTimeout);
// 3. 设置fetchSize(批量获取行数)
setFetchSize(stmt);
return stmt;
} catch (SQLException e) {
closeStatement(stmt);
throw e;
}
}

@Override
public void parameterize(Statement statement) throws SQLException {
// 调用 ParameterHandler 设置参数(处理 ? 占位符)
parameterHandler.setParameters((PreparedStatement) statement);
}

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
// 执行 SQL,获取 ResultSet
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
// 委托 ResultSetHandler 封装结果
return resultSetHandler.handleResultSets(ps);
}
ParameterHandler 核心逻辑(设置参数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// org.apache.ibatis.scripting.defaults.DefaultParameterHandler
@Override
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);
// 跳过输出参数(如存储过程的 OUT 参数)
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
// 1. 获取参数值(从 parameterObject 中获取对应属性值)
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
// 通过 OGNL 表达式获取嵌套属性值(如 user.name)
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
// 2. 获取类型处理器(TypeHandler),负责 Java 类型与 JDBC 类型转换
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
// 3. 设置参数(调用 PreparedStatement.setXxx())
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping, e);
}
}
}
}
}
小结:

此步骤的核心是 “StatementHandler 执行 SQL 预编译和参数设置,与数据库建立实际交互,获取 ResultSet”

步骤 7:ResultSetHandler 封装结果,返回业务对象

ResultSetHandler 负责将 JDBC 的 ResultSet 解析为用户指定的实体类(或 List、Map 等),核心是结果映射(ResultMap) 的应用。

核心源码:DefaultResultSetHandler.handleResultSets()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// org.apache.ibatis.executor.resultset.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;
// 1. 获取第一个 ResultSet
ResultSetWrapper rsw = getFirstResultSet(stmt);

// 2. 获取结果映射(ResultMap)列表(支持多结果集)
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);

while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
// 3. 解析 ResultSet,封装为实体对象
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++;
}
}

// 4. 处理返回结果(单结果/多结果)
return collapseSingleResultList(multipleResults);
}

// 核心:解析 ResultSet 为实体对象
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 defaultResultHandler = new DefaultResultHandler(objectFactory);
// 解析每一行数据,封装为实体
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
multipleResults.add(defaultResultHandler.getResultList());
} else {
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// 关闭 ResultSet
closeResultSet(rsw.getResultSet());
}
}
结果映射核心逻辑(handleRowValues()
  • 简单映射:若实体类属性与数据库列名一致(或开启驼峰映射),直接通过 ResultSet.getObject(columnName) 获取值并设置到实体属性;
  • 复杂映射:若配置了 ResultMap(如字段名与属性名不一致、关联查询),通过 ResultMap 的映射规则匹配列与属性,调用 TypeHandler 完成类型转换;
  • 关联映射:处理一对一(association)、一对多(collection)关联,通过嵌套查询(select 属性)或嵌套结果(join 语句)加载关联数据。
小结:

此步骤的核心是 “将 ResultSet 按 ResultMap 规则解析为业务对象,返回给上层调用者(Mapper 方法)”,完成整个 SQL 执行的闭环。

执行过程总结(核心链路)

MyBatis 从调用 Mapper 方法到返回结果的核心链路可概括为:
MapperProxy(动态代理) → SqlSession → Executor(执行器) → StatementHandler(SQL 执行) → ParameterHandler(参数设置) → 数据库 → ResultSetHandler(结果封装) → 业务对象

关键组件协同关系:

  1. Configuration:全局配置中心,贯穿整个执行过程;
  2. SqlSession:会话入口,持有 Executor;
  3. Executor:执行调度中心,创建三大组件;
  4. StatementHandler:SQL 执行核心,与数据库直接交互;
  5. ParameterHandler/ResultSetHandler:分别负责参数处理和结果处理,是 Executor 与 JDBC 之间的 “转换器”

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10