MyBatis源码解析:从 Mapper 接口到 SQL 执行的完整链路

[复制链接]
发表于 2025-6-27 05:04:37 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
MyBatis 的底层本质是对 JDBC 的封装,因此建议忘记 JDBC 执行流程的同砚回首相干知识。可参考这篇文章:【JDBC 核心执行流程详解】
在 MyBatis 中,常用的查询方式是通过 Mapper 接口署理实现,而非直接调用 sqlSession.selectList 例如:
  1. // Mapper 接口定义
  2. public interface UserMapper {
  3.     List<User> selectUser(@Param("name") String name, @Param("age") Integer age);
  4. }
  5. // 应用层调用(通过代理对象执行)
  6. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  7. List<User> users = mapper.selectUser("coderzpw", 18); // 核心:代理对象处理方法调用
复制代码
接下来文章内容主要围绕上述代码的底层源码逻辑展开讲解
一、Mapper 署理对象的创建:sqlSession.getMapper(UserMapper.class)

当调用 sqlSession.getMapper(UserMapper.class) 时,MyBatis 通过 MapperProxyFactory 创建动态署理对象,涉及到源码如下:
  1. // DefaultSqlSession.java
  2. public <T> T getMapper(Class<T> type) {
  3.   return configuration.<T>getMapper(type, this);
  4. }
复制代码
  1. // Configuration.java
  2. public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  3.   return mapperRegistry.getMapper(type, sqlSession);
  4. }
复制代码
  1. // MapperRegistry.java
  2. public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  3.   // 从已知的Mapper映射中查找对应的Mapper代理工厂
  4.   final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  5.   // 如果找不到对应的Mapper代理工厂,抛出绑定异常
  6.   if (mapperProxyFactory == null) {
  7.     throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  8.   }
  9.   try {
  10.     // 使用代理工厂创建Mapper代理实例
  11.     return mapperProxyFactory.newInstance(sqlSession);
  12.   } catch (Exception e) {
  13.     throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  14.   }
  15. }
复制代码
  1. // MapperProxyFactory.java
  2. public T newInstance(SqlSession sqlSession) {
  3.   // 创建Mapper代理处理器,它实现了InvocationHandler接口
  4.   // 参数1:当前SqlSession,用于执行SQL语句
  5.   // 参数2:Mapper接口类型
  6.   // 参数3:方法缓存,用于缓存Mapper方法对应的SQL语句
  7.   final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
  8.   return newInstance(mapperProxy);
  9. }
  10. protected T newInstance(MapperProxy<T> mapperProxy) {
  11.   // 使用JDK动态代理创建代理对象
  12.   // 参数1:类加载器,使用Mapper接口的类加载器
  13.   // 参数2:代理对象要实现的接口,这里就是Mapper接口
  14.   // 参数3:代理对象的调用处理器,负责处理代理对象方法的调用
  15.   return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  16. }
复制代码
梳理源码逻辑后,执行到 UserMapper mapper = sqlSession.getMapper(UserMapper.class) 时,MyBatis 通过动态署理为 UserMapper 接口生成署理对象,该对象会在后续数据访问中把接口方法调用转为 SQL 执行流程。
二、接口方法的执行:mapper.selectUser(“coderzpw”, 18)

2.1 四大核心组件解析

后续查询由 MyBatis 四大核心组件协同完成:


  • Executor(执行器):控制整体查询流程
  • StatementHandler(语句处理器):准备并执行 SQL
  • ParameterHandler(参数处理器):处理 SQL 参数设置
  • ResultSetHandler(结果集处理器):将查询结果映射为 Java 对象
2.1.1 Executor(执行器):流程控制核心

类层级:
  1. Executor(接口)
  2. ├─ BaseExecutor(抽象类,实现一级缓存 + 事务管理)
  3. │  ├─ SimpleExecutor(默认执行器,每次创建新 Statement)
  4. │  ├─ ReuseExecutor(复用 Statement,基于 SimpleExecutor 扩展)
  5. │  └─ BatchExecutor(批量执行,基于 SimpleExecutor 扩展)
  6. └─ CachingExecutor(二级缓存装饰器,包装 Executor 实现缓存)
复制代码
关键方法:query(处理查询)、update(处理更新)
核心源码片段(BaseExecutor):
  1. public abstract class BaseExecutor implements Executor {
  2.     // 一级缓存(本地缓存)
  3.     private final PerpetualCache localCache = new PerpetualCache("LocalCache");
  4.     // 占位符对象,用于标记正在执行的查询
  5.     private static final Object EXECUTION_PLACEHOLDER = new Object();
  6.     @Override
  7.     public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) {
  8.         BoundSql boundSql = ms.getBoundSql(parameter);
  9.         // 生成缓存键(基于 SQL、参数、RowBounds 等)
  10.         CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
  11.         return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
  12.     }
  13.     public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  14.             // ...
  15.             List<E> list;
  16.             try {
  17.              
  18.               queryStack++;
  19.              
  20.               // 从本地缓存获取结果
  21.               list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
  22.               // 如果缓存命中,处理本地缓存的输出参数(如存储过程的OUT参数)
  23.               if (list != null) {
  24.                 handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
  25.               } else {
  26.                 // 缓存未命中,从数据库查询并缓存结果
  27.                 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
  28.               }
  29.             } finally {
  30.               queryStack--;
  31.             }
  32.             // ...
  33.             // 返回查询结果列表
  34.             return list;
  35.         }
  36.     private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) {
  37.         List<E> list;
  38.         // 先在缓存中放入占位符,标记该查询正在执行
  39.         localCache.putObject(key, EXECUTION_PLACEHOLDER);
  40.         try {
  41.             // 执行实际的数据库查询
  42.             list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
  43.         } finally {
  44.             // 移除占位符
  45.             localCache.removeObject(key);
  46.         }
  47.         // 将实际查询结果存入缓存
  48.         localCache.putObject(key, list);
  49.         
  50.         // 处理存储过程的输出参数(本文示例不涉及)
  51.         if (ms.getStatementType() == StatementType.CALLABLE) {
  52.             localOutputParameterCache.putObject(key, parameter);
  53.         }
  54.         return list;
  55.     }
  56.           
  57.         // 子类实现具体执行逻辑(如 SimpleExecutor 的 doQuery)
  58.         protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException;
  59. }
复制代码
2.1.2 StatementHandler(语句处理器):JDBC 操纵封装

类层级:
  1. StatementHandler(接口)
  2. ├─ BaseStatementHandler(抽象类,实现公共逻辑)
  3. │  ├─ SimpleStatementHandler(处理普通 Statement,无参数)
  4. │  ├─ PreparedStatementHandler(处理预编译 PreparedStatement,带参数)
  5. │  └─ CallableStatementHandler(处理存储过程 CallableStatement)
  6. └─ RoutingStatementHandler(路由类,不直接处理 SQL,仅根据 StatementType 选择具体实现)
复制代码
关键方法:prepare(创建 Statement)、parameterize(设置参数)、query(执行查询)
核心源码片段(BaseExecutor):
  1. public class PreparedStatementHandler extends BaseStatementHandler {
  2.     public PreparedStatementHandler(Executor executor, MappedStatement ms,
  3.                                     Object parameter, RowBounds rowBounds,
  4.                                     ResultHandler resultHandler, BoundSql boundSql) {
  5.         super(executor, ms, parameter, rowBounds, resultHandler, boundSql);
  6.     }
  7.     // 创建预编译 Statement
  8.     @Override
  9.     protected Statement instantiateStatement(Connection connection) throws SQLException {
  10.         String sql = boundSql.getSql();
  11.         
  12.         // 处理需要返回自动生成键的情况(如INSERT语句)
  13.         if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
  14.             String[] keyColumnNames = mappedStatement.getKeyColumns();
  15.             if (keyColumnNames == null) {
  16.                     // 如果没有指定主键列名,使用默认方式返回所有生成的键
  17.                 return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
  18.             } else {
  19.                 // 如果指定了主键列名,只返回这些列的生成键
  20.                 return connection.prepareStatement(sql, keyColumnNames);
  21.             }
  22.         }
  23.         
  24.         // 处理需要指定结果集类型的情况
  25.         else if (mappedStatement.getResultSetType() != null) {
  26.             return connection.prepareStatement(
  27.                 sql,
  28.                 mappedStatement.getResultSetType().getValue(),
  29.                 ResultSet.CONCUR_READ_ONLY  // 设置结果集为只读
  30.             );
  31.         }
  32.         
  33.         // 默认情况,使用标准的PreparedStatement
  34.         else {
  35.             return connection.prepareStatement(sql);
  36.         }
  37.     }
  38.     // 执行查询并处理结果集
  39.     @Override
  40.     public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  41.         PreparedStatement ps = (PreparedStatement) statement;
  42.         // 执行 SQL
  43.         ps.execute();
  44.         // 委托 ResultSetHandler 处理结果集
  45.         return resultSetHandler.handleResultSets(ps);
  46.     }
  47. }
复制代码
2.1.3 ParameterHandler(参数处理器):参数解析与绑定

实现类:DefaultParameterHandler
关键逻辑:将方法参数(如 name 和 age)映射到 SQL 占位符(?),通过 TypeHandler 转换范例
核心源码片段:
  1. public void setParameters(PreparedStatement ps) {
  2.   // 设置错误上下文,记录当前活动为"设置参数",并关联到对应的参数映射ID
  3.   ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
  4.   
  5.   // 获取SQL语句中的参数映射列表
  6.   List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  7.   
  8.   // 遍历参数映射列表,为每个参数设置值
  9.   if (parameterMappings != null) {
  10.     for (int i = 0; i < parameterMappings.size(); i++) {
  11.       ParameterMapping parameterMapping = parameterMappings.get(i);
  12.       
  13.       // 仅处理输入参数(IN或INOUT),忽略输出参数(OUT)
  14.       if (parameterMapping.getMode() != ParameterMode.OUT) {
  15.         Object value;
  16.         String propertyName = parameterMapping.getProperty();
  17.         
  18.         // 1. 首先检查是否为额外参数(如动态SQL中定义的参数)
  19.         if (boundSql.hasAdditionalParameter(propertyName)) {
  20.           value = boundSql.getAdditionalParameter(propertyName);
  21.         }
  22.         // 2. 检查参数对象是否为null
  23.         else if (parameterObject == null) {
  24.           value = null;
  25.         }
  26.         // 3. 检查参数对象是否可以直接使用类型处理器处理(如基本类型)
  27.         else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
  28.           value = parameterObject;
  29.         }
  30.         // 4. 对于复杂对象,使用MetaObject反射获取属性值
  31.         else {
  32.           MetaObject metaObject = configuration.newMetaObject(parameterObject);
  33.           value = metaObject.getValue(propertyName);
  34.         }
  35.         
  36.         // 获取参数的类型处理器和JDBC类型
  37.         TypeHandler typeHandler = parameterMapping.getTypeHandler();
  38.         JdbcType jdbcType = parameterMapping.getJdbcType();
  39.         
  40.         // 处理null值的JDBC类型
  41.         if (value == null && jdbcType == null) {
  42.           jdbcType = configuration.getJdbcTypeForNull();
  43.         }
  44.         
  45.         try {
  46.           // 使用类型处理器将Java对象转换为JDBC参数并设置到PreparedStatement中
  47.           // 注意:JDBC参数索引从1开始,而不是从0开始
  48.           typeHandler.setParameter(ps, i + 1, value, jdbcType);
  49.         } catch (TypeException e) {
  50.           throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
  51.         } catch (SQLException e) {
  52.           throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
  53.         }
  54.       }
  55.     }
  56.   }
  57. }
复制代码
2.1.4 ResultSetHandler(结果集处理器):对象映射引擎

实现类:DefaultResultSetHandler
关键逻辑:将 ResultSet 逐行映射为 Java 对象,支持 ResultMap 设置的字段到属性映射
核心源码片段:
  1. public List<Object> handleResultSets(Statement stmt) throws SQLException {
  2.     // 存储所有结果
  3.     List<Object> results = new ArrayList<>();
  4.    
  5.     // 获取第一个结果集
  6.     ResultSetWrapper rsw = getFirstResultSet(stmt);
  7.     List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  8.    
  9.     // 处理主结果集
  10.     for (ResultMap resultMap : resultMaps) {
  11.         if (rsw == null) break;
  12.         handleResultSet(rsw, resultMap, results, null);
  13.         rsw = getNextResultSet(stmt);
  14.         // ...清理资源
  15.     }
  16.    
  17.     // 处理命名结果集(如存储过程返回的多个结果集)
  18.     String[] resultSets = mappedStatement.getResultSets();
  19.     if (resultSets != null) {
  20.         for (String resultSet : resultSets) {
  21.             if (rsw == null) break;
  22.             ResultMapping mapping = nextResultMaps.get(resultSet);
  23.             if (mapping != null) {
  24.                 ResultMap nestedMap = configuration.getResultMap(mapping.getNestedResultMapId());
  25.                 handleResultSet(rsw, nestedMap, null, mapping);
  26.             }
  27.             rsw = getNextResultSet(stmt);
  28.             // ...清理资源
  29.         }
  30.     }
  31.    
  32.     // 整理结果
  33.     return collapseSingleResultList(results);
  34. }
  35. private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
  36.    try {
  37.        // 处理嵌套结果映射(如一对多关系)
  38.        if (parentMapping != null) {
  39.            handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
  40.        }
  41.        // 处理普通结果集
  42.        else {
  43.            // 使用默认结果处理器收集结果
  44.            if (resultHandler == null) {
  45.                DefaultResultHandler defaultHandler = new DefaultResultHandler(objectFactory);
  46.                handleRowValues(rsw, resultMap, defaultHandler, rowBounds, null);
  47.                multipleResults.add(defaultHandler.getResultList());
  48.            }
  49.            // 使用自定义结果处理器
  50.            else {
  51.                handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
  52.            }
  53.        }
  54.    } finally {
  55.        // 关闭结果集
  56.        closeResultSet(rsw.getResultSet());
  57.    }
  58. }
复制代码
2.2 源码解析-完整调用链路:从 Mapper 方法到结果集的全流程

接下来聚焦 List<User> users = mapper.selectUser("coderzpw", 18) 调用,执行时通过署理对象触发 MapperProxy 的 invoke 方法,进而调用 MapperMethod 的 execute 方法,MyBatis 会依方法签名和参数确定并转换 SQL。
2.2.1 调用链路步调分解

  1. Mapper接口方法调用(如UserMapper.selectUser(name, age))
  2. ├─ 【MapperProxy(代理对象)】
  3. │   ├─ 拦截接口方法调用,触发 invoke() 方法
  4. │   ├─ 从缓存中获取对应的 MapperMethod 对象
  5. │   └─ 调用 mapperMethod.execute(sqlSession, args)
  6. │
  7. ├─ 【MapperMethod】
  8. │   ├─ 根据方法类型(SELECT/INSERT/UPDATE/DELETE)选择执行策略
  9. │   ├─ 解析方法参数,构建参数对象
  10. │   └─ 调用 sqlSession 对应方法(如 selectList/selectOne/insert 等)
  11. │
  12. ├─ 【DefaultSqlSession】
  13. │   └─ 委托 Executor.query() 执行查询(Executor 组件)
  14. │
  15. ├─ 【Executor(SimpleExecutor)】
  16. │   ├─ 创建 StatementHandler(PreparedStatementHandler)
  17. │   ├─ 调用 handler.prepare() 创建 PreparedStatement(含预编译 SQL)
  18. │   ├─ 调用 handler.parameterize() 触发 ParameterHandler 设置参数
  19. │   └─ 调用 handler.query() 执行 SQL,获取 ResultSet
  20. │
  21. ├─ 【StatementHandler(PreparedStatementHandler)】
  22. │   ├─ instantiateStatement() 创建 PreparedStatement(SQL: "select * from user where name = ? and age > ?")
  23. │   ├─ setParameters() 委托 ParameterHandler 绑定参数(name=? 对应 "张三",age=? 对应 20)
  24. │   └─ execute() 执行查询,返回 ResultSet 给 ResultSetHandler
  25. │
  26. ├─ 【ParameterHandler(DefaultParameterHandler)】
  27. │   └─ setParameters() 遍历参数映射,通过 TypeHandler 转换并设置到 PreparedStatement
  28. │
  29. └─ 【ResultSetHandler(DefaultResultSetHandler)】
  30.     ├─ handleResultSets() 遍历 ResultSet 行
  31.     ├─ createResultObject() 创建 User 实例
  32.     └─ 通过反射将列值(name、age 等)设置到 User 对象属性
复制代码
2.2.2 关键源码串联(MyBatis 3.4.6 版本)

步调 1:Mapper 署理对象处理方法调用

  1. // MapperProxy.java
  2. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  3.     try {
  4.         // 处理 Object 类的通用方法(如 toString、equals 等)
  5.         if (Object.class.equals(method.getDeclaringClass())) {
  6.             return method.invoke(this, args);
  7.         }
  8.         // 处理 Java 8 引入的接口默认方法
  9.         else if (isDefaultMethod(method)) {
  10.             return invokeDefaultMethod(proxy, method, args);
  11.         }
  12.     } catch (Throwable t) {
  13.         throw ExceptionUtil.unwrapThrowable(t);
  14.     }
  15.    
  16.     // 对 Mapper 接口定义的方法进行缓存和执行
  17.     final MapperMethod mapperMethod = cachedMapperMethod(method);
  18.     // 执行实际的数据库操作
  19.     return mapperMethod.execute(sqlSession, args);
  20. }
复制代码
  1. // MapperMethod.java
  2. public Object execute(SqlSession sqlSession, Object[] args) {
  3.     Object result;
  4.    
  5.     // 根据 SQL 命令类型选择执行方法
  6.     switch (command.getType()) {
  7.         case INSERT: {
  8.             Object param = method.convertArgsToSqlCommandParam(args);
  9.             result = rowCountResult(sqlSession.insert(command.getName(), param));
  10.             break;
  11.         }
  12.         case UPDATE: {
  13.             Object param = method.convertArgsToSqlCommandParam(args);
  14.             result = rowCountResult(sqlSession.update(command.getName(), param));
  15.             break;
  16.         }
  17.         case DELETE: {
  18.             Object param = method.convertArgsToSqlCommandParam(args);
  19.             result = rowCountResult(sqlSession.delete(command.getName(), param));
  20.             break;
  21.         }
  22.         case SELECT:
  23.             // 处理返回值为 void 且有 ResultHandler 的情况
  24.             if (method.returnsVoid() && method.hasResultHandler()) {
  25.                 executeWithResultHandler(sqlSession, args);
  26.                 result = null;
  27.             }
  28.             // 处理返回值为集合的情况
  29.             else if (method.returnsMany()) {
  30.                 result = executeForMany(sqlSession, args);
  31.             }
  32.             // 处理返回值为 Map 的情况
  33.             else if (method.returnsMap()) {
  34.                 result = executeForMap(sqlSession, args);
  35.             }
  36.             // 处理返回值为 Cursor 的情况
  37.             else if (method.returnsCursor()) {
  38.                 result = executeForCursor(sqlSession, args);
  39.             }
  40.             // 处理返回单个对象的情况
  41.             else {
  42.                 Object param = method.convertArgsToSqlCommandParam(args);
  43.                 result = sqlSession.selectOne(command.getName(), param);
  44.                 // 处理返回值为 Optional 的情况
  45.                 if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) {
  46.                     result = Optional.ofNullable(result);
  47.                 }
  48.             }
  49.             break;
  50.         case FLUSH:
  51.             result = sqlSession.flushStatements();
  52.             break;
  53.         default:
  54.             throw new BindingException("Unknown execution method for: " + command.getName());
  55.     }
  56.    
  57.     // 处理返回值为 null 但不允许 null 的情况
  58.     if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
  59.         throw new BindingException("Mapper method '" + command.getName()
  60.                 + " attempted to return null from a method with a primitive return type ("
  61.                 + method.getReturnType() + ").");
  62.     }
  63.    
  64.     return result;
  65. }
  66. // 处理多参数情况,将参数转换为 SQL 参数
  67. public Object convertArgsToSqlCommandParam(Object[] args) {
  68.     // 无参数
  69.     if (args == null || args.length == 0) {
  70.         return null;
  71.     }
  72.     // 单个参数且无 @Param 注解
  73.     else if (args.length == 1 && !hasNamedParameters) {
  74.         return args[0];
  75.     }
  76.     // 多个参数或有 @Param 注解
  77.     else {
  78.         final Map<String, Object> param = new ParamMap<>();
  79.         int i = 0;
  80.         // 处理 @Param 注解的参数
  81.         for (String name : paramNames) {
  82.             param.put(name, args[i++]);
  83.         }
  84.         // 为参数添加 param1, param2 等键
  85.         if (paramNames.size() < args.length) {
  86.             for (int j = paramNames.size(); j < args.length; j++) {
  87.                 param.put("param" + String.valueOf(j + 1), args[j]);
  88.             }
  89.         }
  90.         return param;
  91.     }
  92. }
复制代码
步调 2:SqlSession 委托 Executor 执行查询

  1. // DefaultSqlSession.java
  2. @Override
  3. public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  4.     try {
  5.         // 根据 statement ID 获取 MappedStatement
  6.         MappedStatement ms = configuration.getMappedStatement(statement);
  7.         
  8.         // 委托 Executor 执行查询
  9.         return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  10.     } catch (Exception e) {
  11.         throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
  12.     } finally {
  13.         ErrorContext.instance().reset();
  14.     }
  15. }
  16. // 处理集合参数
  17. private Object wrapCollection(final Object object) {
  18.     if (object instanceof Collection) {
  19.         StrictMap<Object> map = new StrictMap<>();
  20.         map.put("collection", object);
  21.         if (object instanceof List) {
  22.             map.put("list", object);
  23.         }
  24.         return map;
  25.     } else if (object != null && object.getClass().isArray()) {
  26.         StrictMap<Object> map = new StrictMap<>();
  27.         map.put("array", object);
  28.         return map;
  29.     }
  30.     return object;
  31. }
复制代码
步调 3:Executor 执行查询(以 SimpleExecutor 为例)

  1. // BaseExecutor.java
  2. @Override
  3. public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
  4.     // 获取 BoundSql(包含解析后的 SQL 和参数映射信息)
  5.     BoundSql boundSql = ms.getBoundSql(parameter);
  6.    
  7.     // 创建缓存键(基于 SQL、参数、RowBounds 等)
  8.     CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
  9.    
  10.     // 执行查询(可能从缓存获取)
  11.     return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
  12. }
  13. @Override
  14. public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  15.     ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
  16.    
  17.     // 如果已关闭,抛出异常
  18.     if (closed) {
  19.         throw new ExecutorException("Executor was closed.");
  20.     }
  21.    
  22.     // 先清空本地缓存(针对 select 语句,一级缓存会在查询前清空)
  23.     if (queryStack == 0 && ms.isFlushCacheRequired()) {
  24.         clearLocalCache();
  25.     }
  26.    
  27.     List<E> list;
  28.     try {
  29.         queryStack++;
  30.         
  31.         // 从本地缓存获取结果
  32.         list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
  33.         
  34.         if (list != null) {
  35.             // 处理存储过程的输出参数
  36.             handleLocallyCachedOutputParameters(ms, key, parameter);
  37.         } else {
  38.             // 本地缓存未命中,执行数据库查询
  39.             list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
  40.         }
  41.     } finally {
  42.         queryStack--;
  43.     }
  44.    
  45.     if (queryStack == 0) {
  46.         // 延迟加载队列处理
  47.         for (DeferredLoad deferredLoad : deferredLoads) {
  48.             deferredLoad.load();
  49.         }
  50.         // 清空延迟加载队列
  51.         deferredLoads.clear();
  52.         
  53.         // 一级缓存的作用域是 session,默认情况下,select 语句执行后会清空本地缓存
  54.         if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
  55.             clearLocalCache();
  56.         }
  57.     }
  58.    
  59.     return list;
  60. }
  61. // 从数据库查询
  62. private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  63.     List<E> list;
  64.    
  65.     // 先在缓存中放入占位符,避免递归查询
  66.     localCache.putObject(key, EXECUTION_PLACEHOLDER);
  67.    
  68.     try {
  69.         // 调用子类的 doQuery 方法执行实际查询
  70.         list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
  71.     } finally {
  72.         // 移除占位符
  73.         localCache.removeObject(key);
  74.     }
  75.    
  76.     // 将查询结果放入缓存
  77.     localCache.putObject(key, list);
  78.    
  79.     // 处理存储过程的输出参数
  80.     if (ms.getStatementType() == StatementType.CALLABLE) {
  81.         localOutputParameterCache.putObject(key, parameter);
  82.     }
  83.    
  84.     return list;
  85. }
  86. // SimpleExecutor.java
  87. @Override
  88. public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  89.     Statement stmt = null;
  90.     try {
  91.         Configuration configuration = ms.getConfiguration();
  92.         
  93.         // 创建 StatementHandler(路由到实际的 StatementHandler 实现)
  94.         StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
  95.         
  96.         // 准备 Statement
  97.         stmt = prepareStatement(handler, ms.getStatementLog());
  98.         
  99.         // 执行查询
  100.         return handler.query(stmt, resultHandler);
  101.     } finally {
  102.         // 关闭 Statement
  103.         closeStatement(stmt);
  104.     }
  105. }
  106. // 准备 Statement
  107. private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
  108.     Statement stmt;
  109.     // 获取数据库连接
  110.     Connection connection = getConnection(statementLog);
  111.    
  112.     // 准备 Statement
  113.     stmt = handler.prepare(connection, transaction.getTimeout());
  114.    
  115.     // 设置参数
  116.     handler.parameterize(stmt);
  117.    
  118.     return stmt;
  119. }
复制代码
步调 4:创建 StatementHandler(RoutingStatementHandler)

  1. // Configuration.java
  2. public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  3.     // 创建 StatementHandler(实际创建的是 RoutingStatementHandler)
  4.     StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
  5.    
  6.     // 应用插件(如果有)
  7.     statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
  8.    
  9.     return statementHandler;
  10. }
  11. // RoutingStatementHandler.java
  12. public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  13.     // 根据 StatementType 选择实际的 StatementHandler 实现
  14.     switch (ms.getStatementType()) {
  15.         case STATEMENT:
  16.             delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
  17.             break;
  18.         case PREPARED:
  19.             // 对于预编译语句,使用 PreparedStatementHandler
  20.             delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
  21.             break;
  22.         case CALLABLE:
  23.             delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
  24.             break;
  25.         default:
  26.             throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
  27.     }
  28. }
复制代码
步调 5:StatementHandler 准备 Statement

  1. // BaseStatementHandler.java
  2. @Override
  3. public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
  4.     ErrorContext.instance().sql(boundSql.getSql());
  5.     Statement statement = null;
  6.    
  7.     try {
  8.         // 实例化 Statement
  9.         statement = instantiateStatement(connection);
  10.         
  11.         // 设置超时时间
  12.         setStatementTimeout(statement, transactionTimeout);
  13.         
  14.         // 设置 fetchSize
  15.         setFetchSize(statement);
  16.         
  17.         return statement;
  18.     } catch (SQLException e) {
  19.         closeStatement(statement);
  20.         throw e;
  21.     } catch (Exception e) {
  22.         closeStatement(statement);
  23.         throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
  24.     }
  25. }
  26. // PreparedStatementHandler.java
  27. @Override
  28. protected Statement instantiateStatement(Connection connection) throws SQLException {
  29.     String sql = boundSql.getSql();
  30.    
  31.     // 获取主键生成策略
  32.     if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
  33.         String[] keyColumnNames = mappedStatement.getKeyColumns();
  34.         if (keyColumnNames == null) {
  35.             // 没有指定主键列,使用 JDBC 3.0 规范的方法获取自增主键
  36.             return connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
  37.         } else {
  38.             // 指定了主键列,使用指定的列获取自增主键
  39.             return connection.prepareStatement(sql, keyColumnNames);
  40.         }
  41.     } else if (mappedStatement.getResultSetType() != null) {
  42.         // 设置结果集类型
  43.         return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
  44.     } else {
  45.         // 默认情况,创建预编译语句
  46.         return connection.prepareStatement(sql);
  47.     }
  48. }
复制代码
步调 6:ParameterHandler 设置参数

  1. // BaseStatementHandler.java
  2. @Override
  3. public void parameterize(Statement statement) throws SQLException {
  4.     // 委托 ParameterHandler 设置参数
  5.     parameterHandler.setParameters((PreparedStatement) statement);
  6. }
  7. // DefaultParameterHandler.java
  8. @Override
  9. public void setParameters(PreparedStatement ps) {
  10.     ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
  11.    
  12.     // 获取参数映射列表
  13.     List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  14.    
  15.     if (parameterMappings != null) {
  16.         // 遍历参数映射
  17.         for (int i = 0; i < parameterMappings.size(); i++) {
  18.             ParameterMapping parameterMapping = parameterMappings.get(i);
  19.             
  20.             // 处理非输出参数(存储过程可能有输出参数)
  21.             if (parameterMapping.getMode() != ParameterMode.OUT) {
  22.                 Object value;
  23.                 String propertyName = parameterMapping.getProperty();
  24.                
  25.                 // 处理动态参数(如 _parameter、_databaseId)
  26.                 if (boundSql.hasAdditionalParameter(propertyName)) {
  27.                     value = boundSql.getAdditionalParameter(propertyName);
  28.                 }
  29.                 // 处理参数为 null 的情况
  30.                 else if (parameterObject == null) {
  31.                     value = null;
  32.                 }
  33.                 // 处理参数为基本类型的情况
  34.                 else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
  35.                     value = parameterObject;
  36.                 }
  37.                 // 处理参数为对象或 Map 的情况
  38.                 else {
  39.                     MetaObject metaObject = configuration.newMetaObject(parameterObject);
  40.                     value = metaObject.getValue(propertyName);
  41.                 }
  42.                
  43.                 // 获取类型处理器
  44.                 TypeHandler typeHandler = parameterMapping.getTypeHandler();
  45.                 JdbcType jdbcType = parameterMapping.getJdbcType();
  46.                
  47.                 // 处理 jdbcType 为 null 的情况
  48.                 if (value == null && jdbcType == null) {
  49.                     jdbcType = configuration.getJdbcTypeForNull();
  50.                 }
  51.                
  52.                 try {
  53.                     // 设置参数(核心:类型处理器将 Java 对象转换为 JDBC 类型)
  54.                     typeHandler.setParameter(ps, i + 1, value, jdbcType);
  55.                 } catch (TypeException e) {
  56.                     throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
  57.                 } catch (SQLException e) {
  58.                     throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
  59.                 }
  60.             }
  61.         }
  62.     }
  63. }
复制代码
步调 7:StatementHandler 执行查询

  1. // PreparedStatementHandler.java
  2. @Override
  3. public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  4.     // 转换为 PreparedStatement
  5.     PreparedStatement ps = (PreparedStatement) statement;
  6.    
  7.     // 执行 SQL
  8.     ps.execute();
  9.    
  10.     // 委托 ResultSetHandler 处理结果集
  11.     return resultSetHandler.handleResultSets(ps);
  12. }
复制代码
步调 8:ResultSetHandler 处理结果集

  1. // DefaultResultSetHandler.java
  2. @Override
  3. public List<Object> handleResultSets(Statement stmt) throws SQLException {
  4.     ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
  5.    
  6.     final List<Object> multipleResults = new ArrayList<>();
  7.    
  8.     int resultSetCount = 0;
  9.    
  10.     // 获取第一个结果集
  11.     ResultSet rs = getFirstResultSet(stmt);
  12.    
  13.     // 获取结果映射列表
  14.     List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  15.    
  16.     int resultMapCount = resultMaps.size();
  17.    
  18.     // 验证结果映射数量
  19.     validateResultMapsCount(rs, resultMapCount);
  20.    
  21.     // 处理所有结果集
  22.     while (rs != null && resultMapCount > resultSetCount) {
  23.         ResultMap resultMap = resultMaps.get(resultSetCount);
  24.         
  25.         // 处理单个结果集
  26.         handleResultSet(rs, resultMap, multipleResults, null);
  27.         
  28.         // 获取下一个结果集(适用于存储过程返回多个结果集的情况)
  29.         rs = getNextResultSet(stmt);
  30.         
  31.         // 清理资源
  32.         cleanUpAfterHandlingResultSet();
  33.         
  34.         resultSetCount++;
  35.     }
  36.    
  37.     // 处理结果集映射
  38.     String[] resultSets = mappedStatement.getResultSets();
  39.     if (resultSets != null) {
  40.         while (rs != null && resultSetCount < resultSets.length) {
  41.             // 处理命名结果集
  42.             ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
  43.             if (parentMapping != null) {
  44.                 String nestedResultMapId = parentMapping.getNestedResultMapId();
  45.                 ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
  46.                 handleResultSet(rs, resultMap, null, parentMapping);
  47.             }
  48.             rs = getNextResultSet(stmt);
  49.             cleanUpAfterHandlingResultSet();
  50.             resultSetCount++;
  51.         }
  52.     }
  53.    
  54.     // 处理单个结果集的情况,将其展开为列表
  55.     return collapseSingleResultList(multipleResults);
  56. }
  57. // 处理单个结果集
  58. private void handleResultSet(ResultSet rs, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
  59.     try {
  60.         if (parentMapping != null) {
  61.             // 处理嵌套结果集
  62.             handleRowValues(rs, resultMap, null, RowBounds.DEFAULT, parentMapping);
  63.         } else {
  64.             // 处理普通结果集
  65.             if (resultHandler == null) {
  66.                 // 创建默认结果处理器
  67.                 DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
  68.                
  69.                 // 处理行值
  70.                 handleRowValues(rs, resultMap, defaultResultHandler, rowBounds, null);
  71.                
  72.                 // 将结果添加到多个结果列表中
  73.                 multipleResults.add(defaultResultHandler.getResultList());
  74.             } else {
  75.                 // 使用用户提供的结果处理器
  76.                 handleRowValues(rs, resultMap, resultHandler, rowBounds, null);
  77.             }
  78.         }
  79.     } finally {
  80.         // 关闭结果集
  81.         closeResultSet(rs);
  82.     }
  83. }
  84. // 处理行值
  85. private void handleRowValues(ResultSet rs, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
  86.     if (resultMap.hasNestedResultMaps()) {
  87.         // 处理包含嵌套结果映射的情况
  88.         ensureNoRowBounds();
  89.         checkResultHandler();
  90.         handleRowValuesForNestedResultMap(rs, resultMap, resultHandler, rowBounds, parentMapping);
  91.     } else {
  92.         // 处理简单结果映射的情况
  93.         handleRowValuesForSimpleResultMap(rs, resultMap, resultHandler, rowBounds);
  94.     }
  95. }
  96. // 处理简单结果映射的行值
  97. private void handleRowValuesForSimpleResultMap(ResultSet rs, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds) throws SQLException {
  98.     DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
  99.    
  100.     // 跳过分页偏移量
  101.     skipRows(rs, rowBounds.getOffset());
  102.    
  103.     // 处理行数据
  104.     while (shouldProcessMoreRows(resultContext, rowBounds) && rs.next()) {
  105.         // 获取判别式结果映射(用于动态结果映射)
  106.         ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rs, resultMap, null);
  107.         
  108.         // 获取行值(创建结果对象并填充数据)
  109.         Object rowValue = getRowValue(rs, discriminatedResultMap);
  110.         
  111.         // 将行值添加到结果上下文中
  112.         resultContext.nextResultObject(rowValue);
  113.         
  114.         // 如果有结果处理器,调用它处理结果
  115.         if (resultHandler != null) {
  116.             resultHandler.handleResult(resultContext);
  117.         }
  118.     }
  119. }
  120. // 获取行值(创建结果对象并填充数据)
  121. private Object getRowValue(ResultSet rs, ResultMap resultMap) throws SQLException {
  122.     final ResultLoaderMap lazyLoader = new ResultLoaderMap();
  123.    
  124.     // 创建结果对象
  125.     Object rowValue = createResultObject(rs, resultMap, lazyLoader, null);
  126.    
  127.     if (rowValue != null && !resultMap.isPrimitive()) {
  128.         // 创建元对象
  129.         MetaObject metaObject = configuration.newMetaObject(rowValue);
  130.         
  131.         // 标记是否找到值
  132.         boolean foundValues = this.useConstructorMappings;
  133.         
  134.         // 处理自动映射
  135.         if (shouldApplyAutomaticMappings(resultMap, false)) {
  136.             foundValues = applyAutomaticMappings(rs, resultMap, metaObject, null) || foundValues;
  137.         }
  138.         
  139.         // 处理手动映射
  140.         foundValues = applyPropertyMappings(rs, resultMap, metaObject, lazyLoader, null) || foundValues;
  141.         
  142.         // 如果没有找到任何值且需要非空结果,则返回 null
  143.         foundValues = lazyLoader.size() > 0 || foundValues;
  144.         rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
  145.     }
  146.    
  147.     return rowValue;
  148. }
  149. // 创建结果对象
  150. private Object createResultObject(ResultSet rs, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
  151.     this.useConstructorMappings = false; // 重置构造函数映射标志
  152.    
  153.     // 获取结果类型
  154.     final Class<?> resultType = resultMap.getType();
  155.    
  156.     // 创建元对象处理器
  157.     final List<Class<?>> constructorArgTypes = new ArrayList<>();
  158.     final List<Object> constructorArgs = new ArrayList<>();
  159.    
  160.     // 创建结果对象
  161.     Object resultObject = createResultObject(rs, resultType, constructorArgTypes, constructorArgs, columnPrefix);
  162.    
  163.     // 如果结果类型不是基本类型
  164.     if (resultObject != null && !resultType.isInterface()) {
  165.         // 检查是否有构造函数映射
  166.         if (shouldApplyAutomaticMappings(resultMap, true)) {
  167.             // 应用自动映射
  168.             applyAutomaticMappings(rs, resultMap, configuration.newMetaObject(resultObject), columnPrefix);
  169.         }
  170.         
  171.         // 应用属性映射
  172.         applyPropertyMappings(rs, resultMap, configuration.newMetaObject(resultObject), lazyLoader, columnPrefix);
  173.     }
  174.    
  175.     // 标记使用了构造函数映射
  176.     this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty();
  177.    
  178.     return resultObject;
  179. }
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表