MyBatis 详细执行过程:从源码视角拆解核心流程
MyBatis 的执行过程本质是 “配置解析→核心对象创建→SQL 执行→结果封装” 的闭环,涉及 Configuration、SqlSession、Executor、StatementHandler 等核心组件的协同工作。本文结合 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
| public SqlSessionFactory build(InputStream inputStream) { return build(inputStream, null, null); }
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); return build(parser.parse()); } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException e) { } } }
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.mappedStatements(MappedStatement 封装单条 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
| @Override public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); }
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); 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
| @Override public <T> T getMapper(Class<T> type) { return configuration.getMapper(type, this); }
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
|
动态代理核心:MapperProxy
MapperProxy 实现 InvocationHandler 接口,是 JDK 动态代理的 “调用处理器”,所有 Mapper 方法调用都会触发 invoke 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else { return cachedMapperMethod(method).execute(sqlSession, args); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } }
|
小结:
此步骤的核心是 “通过 JDK 动态代理生成 MapperProxy,将 Mapper 方法调用转发给 SqlSession”,避免手动实现 Mapper 接口。
步骤 4:解析 Mapper 方法,生成 MappedStatement 和 BoundSql
当调用 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
| 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); } break; default: throw new BindingException("Unknown execution method for: " + command.getName()); } return result; }
|
关键对象:MappedStatement 和 BoundSql
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 会创建 StatementHandler、ParameterHandler、ResultSetHandler 三个核心组件,分别负责 SQL 执行、参数设置、结果封装。
以 selectOne 为例,核心源码追踪:
DefaultSqlSession.selectOne() → 调用 selectList() 取第一个结果;
DefaultSqlSession.selectList() → 委托 Executor.query();
Executor.query() → 若开启二级缓存,CachingExecutor 先查缓存,未命中则调用 delegate(如 SimpleExecutor)的 query();
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
| @Override public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } }
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; Connection connection = getConnection(statementLog); stmt = handler.prepare(connection, transaction.getTimeout()); 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 会根据 MappedStatement 的 statementType(默认 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
| @Override public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { ErrorContext.instance().sql(boundSql.getSql()); PreparedStatement stmt = null; try { stmt = connection.prepareStatement(boundSql.getSql(), ms.getStatementType() == StatementType.CALLABLE ? ResultSet.TYPE_SCROLL_INSENSITIVE : ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); setStatementTimeout(stmt, transactionTimeout); setFetchSize(stmt); return stmt; } catch (SQLException e) { closeStatement(stmt); throw e; } }
@Override public void parameterize(Statement statement) throws SQLException { parameterHandler.setParameters((PreparedStatement) statement); }
@Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); 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
| @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); if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { 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, 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
| @Override public List<Object> handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
final List<Object> multipleResults = new ArrayList<>(); int resultSetCount = 0; ResultSetWrapper rsw = getFirstResultSet(stmt);
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()); } }
|
结果映射核心逻辑(handleRowValues())
- 简单映射:若实体类属性与数据库列名一致(或开启驼峰映射),直接通过
ResultSet.getObject(columnName) 获取值并设置到实体属性;
- 复杂映射:若配置了
ResultMap(如字段名与属性名不一致、关联查询),通过 ResultMap 的映射规则匹配列与属性,调用 TypeHandler 完成类型转换;
- 关联映射:处理一对一(
association)、一对多(collection)关联,通过嵌套查询(select 属性)或嵌套结果(join 语句)加载关联数据。
小结:
此步骤的核心是 “将 ResultSet 按 ResultMap 规则解析为业务对象,返回给上层调用者(Mapper 方法)”,完成整个 SQL 执行的闭环。
执行过程总结(核心链路)
MyBatis 从调用 Mapper 方法到返回结果的核心链路可概括为:
MapperProxy(动态代理) → SqlSession → Executor(执行器) → StatementHandler(SQL 执行) → ParameterHandler(参数设置) → 数据库 → ResultSetHandler(结果封装) → 业务对象
关键组件协同关系:
- Configuration:全局配置中心,贯穿整个执行过程;
- SqlSession:会话入口,持有 Executor;
- Executor:执行调度中心,创建三大组件;
- StatementHandler:SQL 执行核心,与数据库直接交互;
- ParameterHandler/ResultSetHandler:分别负责参数处理和结果处理,是 Executor 与 JDBC 之间的 “转换器”
v1.3.10