MyBatis SQL 执行过程原理分析(附源码) 代理层:Mapper 接口动态代理 路由层:MapperMethod 分发 核心引擎:SqlSession 执行

MyBatis SQL 执行过程原理分析(附源码)

  • 1. 代理层:Mapper 接口动态代理
  • 2. 路由层:MapperMethod 分发
  • 3. 核心引擎:SqlSession 执行
  • 4. 执行器:Executor 调度
  • 5. 处理器层:StatementHandler 执行
  • 6. 结果映射:ResultSetHandler 转换
      • 核心执行流程图
      • 关键设计亮点
      • 性能优化建议

MyBatis 的 SQL 执行过程可以分为 6 个核心阶段,我们将通过源码逐层分析:

1. 代理层:Mapper 接口动态代理

当调用 SqlSession.getMapper() 时,MyBatis 通过 MapperProxyFactory 创建接口的代理对象:

// org.apache.ibatis.binding.MapperProxyFactory
public class MapperProxyFactory<T> {
    public T newInstance(SqlSession sqlSession) {
        final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
    }
}

// org.apache.ibatis.binding.MapperProxy
public class MapperProxy<T> implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 创建 MapperMethod 执行器
        final MapperMethod mapperMethod = cachedMapperMethod(method);
        return mapperMethod.execute(sqlSession, args); // 进入核心执行流程
    }
}

2. 路由层:MapperMethod 分发

MapperMethod 根据方法签名选择执行策略:

// org.apache.ibatis.binding.MapperMethod
public class MapperMethod {
    public Object execute(SqlSession sqlSession, Object[] args) {
        switch (command.getType()) {
            case INSERT: 
                return sqlSession.insert(command.getName(), param);
            case UPDATE:
                return sqlSession.update(...);
            case SELECT:
                if (method.returnsVoid()) {
                    sqlSession.select(...);
                } else {
                    return sqlSession.selectOne(...); // 以查询为例
                }
            // ... DELETE 等其他操作
        }
    }
}

3. 核心引擎:SqlSession 执行

DefaultSqlSession 委托给 Executor 执行:

// org.apache.ibatis.session.defaults.DefaultSqlSession
public class DefaultSqlSession implements SqlSession {
    @Override
    public <T> T selectOne(String statement, Object parameter) {
        List<T> list = this.selectList(statement, parameter);
        if (list.size() == 1) return list.get(0);
        if (list.size() > 1) throw new TooManyResultsException();
        return null;
    }
    
    @Override
    public <E> List<E> selectList(String statement, Object parameter) {
        // 获取预编译的SQL对象
        MappedStatement ms = configuration.getMappedStatement(statement);
        // 委托Executor执行
        return executor.query(ms, wrapCollection(parameter), RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
    }
}

4. 执行器:Executor 调度

BaseExecutor 实现缓存和事务管理:

// org.apache.ibatis.executor.BaseExecutor
public abstract class BaseExecutor implements Executor {
    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        // 1. 获取BoundSql(包含解析后的SQL和参数)
        BoundSql boundSql = ms.getBoundSql(parameter);
        
        // 2. 创建缓存Key
        CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
        
        // 3. 查询数据库(核心方法)
        return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }

    private <E> List<E> queryFromDatabase(...) {
        // 实际执行SQL的方法
        list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        // 放入本地缓存(一级缓存)
        localCache.putObject(key, list);
        return list;
    }
}

5. 处理器层:StatementHandler 执行

具体执行由子类 PreparedStatementHandler 完成:

// org.apache.ibatis.executor.statement.PreparedStatementHandler
public class PreparedStatementHandler extends BaseStatementHandler {
    @Override
    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        ps.execute(); // JDBC 执行SQL
        
        // 结果集处理
        return resultSetHandler.handleResultSets(ps);
    }
    
    @Override
    protected Statement instantiateStatement(Connection connection) throws SQLException {
        String sql = boundSql.getSql();
        // 关键步骤:创建 PreparedStatement
        return connection.prepareStatement(sql, ...);
    }
}

6. 结果映射:ResultSetHandler 转换

将 ResultSet 映射为 Java 对象:

// org.apache.ibatis.executor.resultset.DefaultResultSetHandler
public class DefaultResultSetHandler implements ResultSetHandler {
    @Override
    public List<Object> handleResultSets(Statement stmt) throws SQLException {
        final List<Object> multipleResults = new ArrayList<>();
        ResultSet rs = stmt.getResultSet();
        
        // 遍历结果集
        while (rs != null) {
            // 获取结果映射配置
            ResultMap resultMap = mappedStatement.getResultMap();
            
            // 构建结果对象
            while (rs.next()) {
                Object rowValue = getRowValue(rs, resultMap);
                multipleResults.add(rowValue);
            }
            rs = getNextResultSet(stmt);
        }
        return collapseSingleResultList(multipleResults);
    }
    
    private Object getRowValue(ResultSet rs, ResultMap resultMap) throws SQLException {
        // 创建目标对象实例
        Object resultObject = createResultObject(rs, resultMap, null);
        
        // 应用自动映射
        applyAutomaticMappings(rs, resultObject, null);
        
        // 应用手动映射
        applyPropertyMappings(rs, resultObject, ...);
        return resultObject;
    }
}

核心执行流程图

客户端 MapperProxy MapperMethod SqlSession Executor StatementHandler ResultHandler 调用Mapper方法 创建方法执行器 调用select/update 执行query/update 创建Statement 设置参数 执行SQL 处理结果集 返回映射结果 返回结果 返回结果 返回结果 返回结果 客户端 MapperProxy MapperMethod SqlSession Executor StatementHandler ResultHandler

关键设计亮点

  1. 三层缓存机制

    • MapperProxy 缓存 MapperMethod
    • Executor 实现一级缓存
    • MappedStatement 支持二级缓存
  2. 插件拦截点

    // 核心拦截点签名
    @Intercepts({
      @Signature(type=Executor.class, method="query",...),
      @Signature(type=StatementHandler.class, method="prepare",...)
    })
    

    可在 SQL 执行前后插入自定义逻辑

  3. 动态 SQL 处理
    BoundSql 包含最终执行的 SQL 和参数映射:

    public class BoundSql {
        private String sql;              // 解析后的SQL
        private List<ParameterMapping> parameterMappings;
        private Object parameterObject;  // 原始参数
    }
    
  4. 延迟加载
    ResultLoaderMap 通过动态代理实现关联对象的延迟加载


性能优化建议

  1. 避免 N+1 查询
    使用 的嵌套结果映射代替多次查询

  2. 重用 Executor

    // 批量操作时使用 BatchExecutor
    SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
    
  3. 合理设置 fetchSize

    <select id="selectLargeData" fetchSize="1000">
      SELECT * FROM large_table
    select>
    
  4. 结果集流式处理

    try (SqlSession session = sqlSessionFactory.openSession()) {
        try (Cursor<Order> cursor = session.selectCursor("selectOrders")) {
            cursor.forEach(order -> process(order));
        }
    }
    

通过理解 MyBatis 的分层设计和核心源码实现,可以更好地进行性能调优和问题排查。

你可能感兴趣的:(mybatis,sql,数据库,数据库架构,java,spring,boot,db)