mybatis详细执行过程
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:
// 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.mappedStatements(MappedStatement封装单条 SQL 的完整信息); - 全局设置(settings):如
cacheEnabled(二级缓存开关)、mapUnderscoreToCamelCase(驼峰映射),存入Configuration对应属性; - 类型别名(typeAliases):解析别名映射,存入
Configuration.typeAliasRegistry。
小结:
此步骤的核心是 “将 XML 配置转化为内存中的 Configuration 对象”,后续所有核心组件的创建都依赖该对象。
步骤 2:创建 SqlSession(数据库会话)
SqlSession 相当于 JDBC 的 Connection,代表一次数据库会话,通过 SqlSessionFactory.openSession() 创建,生命周期为单次业务请求(线程不安全,需及时关闭)。
核心源码:DefaultSqlSessionFactory.openSession()
// org.mybatis.session.defaults.DefaultSqlSessionFactory
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()
// org.mybatis.session.defaults.DefaultSqlSession
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 方法:
// org.apache.ibatis.binding.MapperProxy
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 方法,生成 MappedStatement 和 BoundSql
当调用 Mapper 方法(如 userMapper.selectById(1))时,MyBatis 会先解析该方法对应的 MappedStatement(封装 SQL 元信息)和 BoundSql(封装解析后的 SQL 和参数)。
核心源码:MapperMethod.execute()
// 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;
}
关键对象: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()
// org.apache.ibatis.executor.SimpleExecutor
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 会根据 MappedStatement 的 statementType(默认 PREPARED)选择具体的 StatementHandler 实现,以 PreparedStatementHandler 为例:
// org.apache.ibatis.executor.statement.PreparedStatementHandler
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;
}
}
public void parameterize(Statement statement) throws SQLException {
// 调用 ParameterHandler 设置参数(处理 ? 占位符)
parameterHandler.setParameters((PreparedStatement) statement);
}
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 核心逻辑(设置参数)
// org.apache.ibatis.scripting.defaults.DefaultParameterHandler
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()
// org.apache.ibatis.executor.resultset.DefaultResultSetHandler
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(结果封装) → 业务对象
关键组件协同关系:
- Configuration:全局配置中心,贯穿整个执行过程;
- SqlSession:会话入口,持有 Executor;
- Executor:执行调度中心,创建三大组件;
- StatementHandler:SQL 执行核心,与数据库直接交互;
- ParameterHandler/ResultSetHandler:分别负责参数处理和结果处理,是 Executor 与 JDBC 之间的 “转换器”