知其然要知其所以然,探索每一个知识点背后的意义,你知道的越多,你不知道的越多,一起学习,一起进步,如果文章感觉对您有用的话,关注、收藏、点赞,有困惑的地方请评论,我们一起交流!
一、MyBatis SQL 执行流程图
sequenceDiagram
    participant Client
    participant MapperProxy
    participant SqlSession
    participant Executor
    participant StatementHandler
    participant ParameterHandler
    participant ResultSetHandler
    participant JDBC
    Client->>MapperProxy: 调用Mapper接口方法
    MapperProxy->>SqlSession: 获取SqlSession实例
    SqlSession->>Executor: 委托执行
    Executor->>Executor: 处理缓存(一级/二级)
    Executor->>StatementHandler: 创建Statement
    StatementHandler->>ParameterHandler: 设置参数
    ParameterHandler->>JDBC: 填充PreparedStatement参数
    JDBC->>JDBC: 执行SQL
    JDBC->>ResultSetHandler: 返回ResultSet
    ResultSetHandler->>Executor: 转换为Java对象
    Executor->>SqlSession: 返回结果
    SqlSession->>MapperProxy: 返回结果
    MapperProxy->>Client: 返回结果
二、流程详解与源码分析
1. Mapper 接口方法调用(动态代理)
- 
入口类 :
MapperProxy(动态代理类) - 
源码路径 :
org.apache.ibatis.binding.MapperProxy - 
核心逻辑 :
javapublic Object invoke(Object proxy, Method method, Object[] args) { // 1. 解析方法签名 MapperMethod mapperMethod = cachedMapperMethod(method); // 2. 调用 SqlSession 执行 SQL return mapperMethod.execute(sqlSession, args); } 
2. SqlSession 委托执行
- 
核心类 :
DefaultSqlSession - 
源码路径 :
org.apache.ibatis.session.defaults.DefaultSqlSession - 
关键方法 :
javapublic <E> List<E> selectList(String statement, Object parameter) { // 获取 MappedStatement(包含 SQL 定义) MappedStatement ms = configuration.getMappedStatement(statement); // 委托给 Executor 执行 return executor.query(ms, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER); } 
3. Executor 处理缓存与执行
- 
核心类 :
BaseExecutor(抽象基类) - 
源码路径 :
org.apache.ibatis.executor.BaseExecutor - 
关键逻辑 :
javapublic <E> List<E> query(MappedStatement ms, Object parameter, ...) { // 1. 生成缓存 Key CacheKey key = createCacheKey(ms, parameter, ...); // 2. 检查一级缓存 if (ms.isUseCache() && cache != null) { List<E> cachedList = (List<E>) cache.getObject(key); if (cachedList != null) return cachedList; } // 3. 未命中缓存,执行查询 return queryFromDatabase(ms, parameter, ...); } private <E> List<E> queryFromDatabase(...) { // 调用 doQuery()(子类实现) List<E> list = doQuery(ms, parameter, ...); // 写入一级缓存 if (ms.isUseCache()) cache.putObject(key, list); return list; } 
4. StatementHandler 创建 Statement
- 
核心类 :
PreparedStatementHandler - 
源码路径 :
org.apache.ibatis.executor.statement.PreparedStatementHandler - 
关键方法 :
javapublic <E> List<E> query(Statement statement, ResultHandler resultHandler) { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); // 处理结果集 return resultSetHandler.handleResultSets(ps); } 
5. ParameterHandler 参数绑定
- 
核心类 :
DefaultParameterHandler - 
源码路径 :
org.apache.ibatis.scripting.defaults.DefaultParameterHandler - 
关键逻辑 :
javapublic void setParameters(PreparedStatement ps) { // 遍历参数映射,逐个设置参数 for (ParameterMapping paramMapping : parameterMappings) { Object value = ...; // 从参数对象中提取值 TypeHandler typeHandler = paramMapping.getTypeHandler(); typeHandler.setParameter(ps, i + 1, value, paramMapping.getJdbcType()); } } 
6. ResultSetHandler 结果映射
- 
核心类 :
DefaultResultSetHandler - 
源码路径 :
org.apache.ibatis.executor.resultset.DefaultResultSetHandler - 
关键逻辑 :
javapublic List<Object> handleResultSets(Statement stmt) { // 遍历 ResultSet,逐行映射为 Java 对象 while (rsw != null && resultMapCount > resultSetIndex) { ResultMap resultMap = resultMaps.get(resultSetIndex); Object rowValue = getRowValue(rsw, resultMap); addToResultMap(rowValue); } return resultList; } 
三、核心类图与交互
            
            
              plaintext
              
              
            
          
          MapperProxy → SqlSession → Executor → StatementHandler → JDBC
                                  ↑           ↓
                                Cache   ResultSetHandler
        四、关键设计模式
- 动态代理模式 :
MapperProxy拦截接口方法调用。 - 模板方法模式 :
BaseExecutor定义执行流程,子类实现具体逻辑。 - 装饰器模式 :
CachingExecutor包装普通 Executor 添加缓存功能。 - 责任链模式 :
InterceptorChain管理插件拦截逻辑。 
五、调试技巧与实战示例
1. 断点设置
- MapperProxy.invoke():观察方法调用如何转换为 SQL 操作。
 - PreparedStatementHandler.query():跟踪 JDBC 执行过程。
 - DefaultResultSetHandler.handleResultSets():分析结果集映射逻辑。
 
2. 日志输出
在 mybatis-config.xml 中开启 Debug 日志:
            
            
              xml
              
              
            
          
          <configuration>
  <settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
  </settings>
</configuration>
        3. 实战示例:跟踪 SELECT 查询
            
            
              java
              
              
            
          
          // Mapper 接口
public interface UserMapper {
  @Select("SELECT * FROM users WHERE id = #{id}")
  User getUserById(int id);
}
// 调用代码
User user = sqlSession.getMapper(UserMapper.class).getUserById(1);
        - 执行路径 : 
MapperProxy→DefaultSqlSession.selectOne()→CachingExecutor.query()→PreparedStatementHandler.query()→DefaultResultSetHandler.handleResultSets(). 
六、高级特性扩展
1. 插件拦截 SQL 执行
- 
拦截点 :
Executor、StatementHandler、ParameterHandler、ResultSetHandler。 - 
示例插件 :统计 SQL 执行时间。
java@Intercepts(@Signature(type = Executor.class, method = "query", args = {...})) public class SqlTimeInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { long start = System.currentTimeMillis(); Object result = invocation.proceed(); System.out.println("SQL 耗时: " + (System.currentTimeMillis() - start) + "ms"); return result; } } 
2. 自定义类型处理器
- 
核心接口 :
TypeHandler<T> - 
示例 :处理枚举类型存储为字符串。
javapublic class EnumTypeHandler<E extends Enum<E>> implements TypeHandler<E> { @Override public void setParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) { ps.setString(i, parameter.name()); } @Override public E getResult(ResultSet rs, String columnName) { String value = rs.getString(columnName); return Enum.valueOf(type, value); } } 
七、总结
通过以上流程分析,可以清晰看到 MyBatis 如何将 Mapper 接口的方法调用转化为 JDBC 操作。核心在于:
- 动态代理:将接口调用映射到 SQL 执行。
 - 执行器链 :通过 
Executor实现缓存、事务管理。 - 结果映射 :灵活地将 
ResultSet转为 Java 对象。