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

发布于:2025-06-05 ⋅ 阅读:(33) ⋅ 点赞:(0)

MyBatis 的底层本质是对 JDBC 的封装,因此建议忘记 JDBC 执行流程的同学回顾相关知识。可参考这篇文章:【JDBC 核心执行流程详解】

MyBatis 中,常用的查询方式是通过 Mapper 接口代理实现,而非直接调用 sqlSession.selectList 例如:

// Mapper 接口定义
public interface UserMapper {
    List<User> selectUser(@Param("name") String name, @Param("age") Integer age);
}

// 应用层调用(通过代理对象执行)
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.selectUser("coderzpw", 18); // 核心:代理对象处理方法调用

接下来文章内容主要围绕上述代码的底层源码逻辑展开讲解

一、Mapper 代理对象的创建:sqlSession.getMapper(UserMapper.class)

当调用 sqlSession.getMapper(UserMapper.class) 时,MyBatis 通过 MapperProxyFactory 创建动态代理对象,涉及到源码如下:

// DefaultSqlSession.java
public <T> T getMapper(Class<T> type) {
  return configuration.<T>getMapper(type, this);
}
// Configuration.java
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  return mapperRegistry.getMapper(type, sqlSession);
}
// MapperRegistry.java
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  // 从已知的Mapper映射中查找对应的Mapper代理工厂
  final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  // 如果找不到对应的Mapper代理工厂,抛出绑定异常
  if (mapperProxyFactory == null) {
    throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  }
  try {
    // 使用代理工厂创建Mapper代理实例
    return mapperProxyFactory.newInstance(sqlSession);
  } catch (Exception e) {
    throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  }
}
// MapperProxyFactory.java

public T newInstance(SqlSession sqlSession) {
  // 创建Mapper代理处理器,它实现了InvocationHandler接口
  // 参数1:当前SqlSession,用于执行SQL语句
  // 参数2:Mapper接口类型
  // 参数3:方法缓存,用于缓存Mapper方法对应的SQL语句
  final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
  return newInstance(mapperProxy);
}

protected T newInstance(MapperProxy<T> mapperProxy) {
  // 使用JDK动态代理创建代理对象
  // 参数1:类加载器,使用Mapper接口的类加载器
  // 参数2:代理对象要实现的接口,这里就是Mapper接口
  // 参数3:代理对象的调用处理器,负责处理代理对象方法的调用
  return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

梳理源码逻辑后,执行到 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(执行器):流程控制核心

类层级:

Executor(接口)
├─ BaseExecutor(抽象类,实现一级缓存 + 事务管理)
│  ├─ SimpleExecutor(默认执行器,每次创建新 Statement)
│  ├─ ReuseExecutor(复用 Statement,基于 SimpleExecutor 扩展)
│  └─ BatchExecutor(批量执行,基于 SimpleExecutor 扩展)
└─ CachingExecutor(二级缓存装饰器,包装 Executor 实现缓存)

关键方法:query(处理查询)、update(处理更新)

核心源码片段(BaseExecutor):

public abstract class BaseExecutor implements Executor {
    // 一级缓存(本地缓存)
    private final PerpetualCache localCache = new PerpetualCache("LocalCache");
    // 占位符对象,用于标记正在执行的查询
    private static final Object EXECUTION_PLACEHOLDER = new Object();

    @Override
    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) {
        BoundSql boundSql = ms.getBoundSql(parameter);
        // 生成缓存键(基于 SQL、参数、RowBounds 等)
        CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
        return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }

    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
	    // ...
	    List<E> list;
	    try {
	      
	      queryStack++;
	      
	      // 从本地缓存获取结果
	      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
	      // 如果缓存命中,处理本地缓存的输出参数(如存储过程的OUT参数)
	      if (list != null) {
	        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
	      } else {
	        // 缓存未命中,从数据库查询并缓存结果
	        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
	      }
	    } finally {
	      queryStack--;
	    }
	    // ...
	    // 返回查询结果列表
	    return list;
	}

    private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) {
        List<E> list;
        // 先在缓存中放入占位符,标记该查询正在执行
        localCache.putObject(key, EXECUTION_PLACEHOLDER);
        try {
            // 执行实际的数据库查询
            list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
            // 移除占位符
            localCache.removeObject(key);
        }
        // 将实际查询结果存入缓存
        localCache.putObject(key, list);
        
        // 处理存储过程的输出参数(本文示例不涉及)
        if (ms.getStatementType() == StatementType.CALLABLE) {
            localOutputParameterCache.putObject(key, parameter);
        }
        return list;
    }

	  
	// 子类实现具体执行逻辑(如 SimpleExecutor 的 doQuery)
	protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException;
}

2.1.2 StatementHandler(语句处理器):JDBC 操作封装

类层级:

StatementHandler(接口)
├─ BaseStatementHandler(抽象类,实现公共逻辑)
│  ├─ SimpleStatementHandler(处理普通 Statement,无参数)
│  ├─ PreparedStatementHandler(处理预编译 PreparedStatement,带参数)
│  └─ CallableStatementHandler(处理存储过程 CallableStatement)
└─ RoutingStatementHandler(路由类,不直接处理 SQL,仅根据 StatementType 选择具体实现)

关键方法:prepare(创建 Statement)、parameterize(设置参数)、query(执行查询)

核心源码片段(BaseExecutor):

public class PreparedStatementHandler extends BaseStatementHandler {
    public PreparedStatementHandler(Executor executor, MappedStatement ms, 
                                    Object parameter, RowBounds rowBounds, 
                                    ResultHandler resultHandler, BoundSql boundSql) {
        super(executor, ms, parameter, rowBounds, resultHandler, boundSql);
    }

    // 创建预编译 Statement
    @Override
    protected Statement instantiateStatement(Connection connection) throws SQLException {
        String sql = boundSql.getSql();
        
        // 处理需要返回自动生成键的情况(如INSERT语句)
        if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
            String[] keyColumnNames = mappedStatement.getKeyColumns();
            if (keyColumnNames == null) {
            	// 如果没有指定主键列名,使用默认方式返回所有生成的键
                return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
            } else {
                // 如果指定了主键列名,只返回这些列的生成键
                return connection.prepareStatement(sql, keyColumnNames);
            }
        } 
        
        // 处理需要指定结果集类型的情况
        else if (mappedStatement.getResultSetType() != null) {
            return connection.prepareStatement(
                sql, 
                mappedStatement.getResultSetType().getValue(), 
                ResultSet.CONCUR_READ_ONLY  // 设置结果集为只读
            );
        } 
        
        // 默认情况,使用标准的PreparedStatement
        else {
            return connection.prepareStatement(sql);
        }
    }

    // 执行查询并处理结果集
    @Override
    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        // 执行 SQL
        ps.execute(); 
        // 委托 ResultSetHandler 处理结果集
        return resultSetHandler.handleResultSets(ps);
    }
}

2.1.3 ParameterHandler(参数处理器):参数解析与绑定

实现类:DefaultParameterHandler
关键逻辑:将方法参数(如 nameage)映射到 SQL 占位符(?),通过 TypeHandler 转换类型
核心源码片段

public void setParameters(PreparedStatement ps) {
  // 设置错误上下文,记录当前活动为"设置参数",并关联到对应的参数映射ID
  ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
  
  // 获取SQL语句中的参数映射列表
  List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
  
  // 遍历参数映射列表,为每个参数设置值
  if (parameterMappings != null) {
    for (int i = 0; i < parameterMappings.size(); i++) {
      ParameterMapping parameterMapping = parameterMappings.get(i);
      
      // 仅处理输入参数(IN或INOUT),忽略输出参数(OUT)
      if (parameterMapping.getMode() != ParameterMode.OUT) {
        Object value;
        String propertyName = parameterMapping.getProperty();
        
        // 1. 首先检查是否为额外参数(如动态SQL中定义的参数)
        if (boundSql.hasAdditionalParameter(propertyName)) {
          value = boundSql.getAdditionalParameter(propertyName);
        } 
        // 2. 检查参数对象是否为null
        else if (parameterObject == null) {
          value = null;
        } 
        // 3. 检查参数对象是否可以直接使用类型处理器处理(如基本类型)
        else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
          value = parameterObject;
        } 
        // 4. 对于复杂对象,使用MetaObject反射获取属性值
        else {
          MetaObject metaObject = configuration.newMetaObject(parameterObject);
          value = metaObject.getValue(propertyName);
        }
        
        // 获取参数的类型处理器和JDBC类型
        TypeHandler typeHandler = parameterMapping.getTypeHandler();
        JdbcType jdbcType = parameterMapping.getJdbcType();
        
        // 处理null值的JDBC类型
        if (value == null && jdbcType == null) {
          jdbcType = configuration.getJdbcTypeForNull();
        }
        
        try {
          // 使用类型处理器将Java对象转换为JDBC参数并设置到PreparedStatement中
          // 注意:JDBC参数索引从1开始,而不是从0开始
          typeHandler.setParameter(ps, i + 1, value, jdbcType);
        } catch (TypeException e) {
          throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
        } catch (SQLException e) {
          throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
        }
      }
    }
  }
}

2.1.4 ResultSetHandler(结果集处理器):对象映射引擎

实现类:DefaultResultSetHandler
关键逻辑:将 ResultSet 逐行映射为 Java 对象,支持 ResultMap 配置的字段到属性映射
核心源码片段:

public List<Object> handleResultSets(Statement stmt) throws SQLException {
    // 存储所有结果
    List<Object> results = new ArrayList<>();
    
    // 获取第一个结果集
    ResultSetWrapper rsw = getFirstResultSet(stmt);
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    
    // 处理主结果集
    for (ResultMap resultMap : resultMaps) {
        if (rsw == null) break;
        handleResultSet(rsw, resultMap, results, null);
        rsw = getNextResultSet(stmt);
        // ...清理资源
    }
    
    // 处理命名结果集(如存储过程返回的多个结果集)
    String[] resultSets = mappedStatement.getResultSets();
    if (resultSets != null) {
        for (String resultSet : resultSets) {
            if (rsw == null) break;
            ResultMapping mapping = nextResultMaps.get(resultSet);
            if (mapping != null) {
                ResultMap nestedMap = configuration.getResultMap(mapping.getNestedResultMapId());
                handleResultSet(rsw, nestedMap, null, mapping);
            }
            rsw = getNextResultSet(stmt);
            // ...清理资源
        }
    }
    
    // 整理结果
    return collapseSingleResultList(results);
}


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 defaultHandler = new DefaultResultHandler(objectFactory);
               handleRowValues(rsw, resultMap, defaultHandler, rowBounds, null);
               multipleResults.add(defaultHandler.getResultList());
           } 
           // 使用自定义结果处理器
           else {
               handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
           }
       }
   } finally {
       // 关闭结果集
       closeResultSet(rsw.getResultSet());
   }
}

2.2 源码解析-完整调用链路:从 Mapper 方法到结果集的全流程

接下来聚焦 List<User> users = mapper.selectUser("coderzpw", 18) 调用,执行时通过代理对象触发 MapperProxyinvoke 方法,进而调用 MapperMethodexecute 方法,MyBatis 会依方法签名和参数确定并转换 SQL

2.2.1 调用链路步骤分解

Mapper接口方法调用(如UserMapper.selectUser(name, age))
├─ 【MapperProxy(代理对象)】
│   ├─ 拦截接口方法调用,触发 invoke() 方法
│   ├─ 从缓存中获取对应的 MapperMethod 对象
│   └─ 调用 mapperMethod.execute(sqlSession, args)
│
├─ 【MapperMethod】
│   ├─ 根据方法类型(SELECT/INSERT/UPDATE/DELETE)选择执行策略
│   ├─ 解析方法参数,构建参数对象
│   └─ 调用 sqlSession 对应方法(如 selectList/selectOne/insert 等)
│
├─ 【DefaultSqlSession】
│   └─ 委托 Executor.query() 执行查询(Executor 组件)
│
├─ 【ExecutorSimpleExecutor)】
│   ├─ 创建 StatementHandlerPreparedStatementHandler)
│   ├─ 调用 handler.prepare() 创建 PreparedStatement(含预编译 SQL)
│   ├─ 调用 handler.parameterize() 触发 ParameterHandler 设置参数
│   └─ 调用 handler.query() 执行 SQL,获取 ResultSet
│
├─ 【StatementHandlerPreparedStatementHandler)】
│   ├─ instantiateStatement() 创建 PreparedStatementSQL: "select * from user where name = ? and age > ?")
│   ├─ setParameters() 委托 ParameterHandler 绑定参数(name=? 对应 "张三",age=? 对应 20)
│   └─ execute() 执行查询,返回 ResultSetResultSetHandler
│
├─ 【ParameterHandlerDefaultParameterHandler)】
│   └─ setParameters() 遍历参数映射,通过 TypeHandler 转换并设置到 PreparedStatement
│
└─ 【ResultSetHandlerDefaultResultSetHandler)】
    ├─ handleResultSets() 遍历 ResultSet 行
    ├─ createResultObject() 创建 User 实例
    └─ 通过反射将列值(name、age 等)设置到 User 对象属性

2.2.2 关键源码串联(MyBatis 3.4.6 版本)

步骤 1:Mapper 代理对象处理方法调用
// MapperProxy.java
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        // 处理 Object 类的通用方法(如 toString、equals 等)
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        } 
        // 处理 Java 8 引入的接口默认方法
        else if (isDefaultMethod(method)) {
            return invokeDefaultMethod(proxy, method, args);
        }
    } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
    }
    
    // 对 Mapper 接口定义的方法进行缓存和执行
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    // 执行实际的数据库操作
    return mapperMethod.execute(sqlSession, args);
}
// MapperMethod.java
public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    
    // 根据 SQL 命令类型选择执行方法
    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:
            // 处理返回值为 void 且有 ResultHandler 的情况
            if (method.returnsVoid() && method.hasResultHandler()) {
                executeWithResultHandler(sqlSession, args);
                result = null;
            }
            // 处理返回值为集合的情况
            else if (method.returnsMany()) {
                result = executeForMany(sqlSession, args);
            }
            // 处理返回值为 Map 的情况
            else if (method.returnsMap()) {
                result = executeForMap(sqlSession, args);
            }
            // 处理返回值为 Cursor 的情况
            else if (method.returnsCursor()) {
                result = executeForCursor(sqlSession, args);
            }
            // 处理返回单个对象的情况
            else {
                Object param = method.convertArgsToSqlCommandParam(args);
                result = sqlSession.selectOne(command.getName(), param);
                // 处理返回值为 Optional 的情况
                if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) {
                    result = Optional.ofNullable(result);
                }
            }
            break;
        case FLUSH:
            result = sqlSession.flushStatements();
            break;
        default:
            throw new BindingException("Unknown execution method for: " + command.getName());
    }
    
    // 处理返回值为 null 但不允许 null 的情况
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
        throw new BindingException("Mapper method '" + command.getName() 
                + " attempted to return null from a method with a primitive return type (" 
                + method.getReturnType() + ").");
    }
    
    return result;
}

// 处理多参数情况,将参数转换为 SQL 参数
public Object convertArgsToSqlCommandParam(Object[] args) {
    // 无参数
    if (args == null || args.length == 0) {
        return null;
    }
    // 单个参数且无 @Param 注解
    else if (args.length == 1 && !hasNamedParameters) {
        return args[0];
    }
    // 多个参数或有 @Param 注解
    else {
        final Map<String, Object> param = new ParamMap<>();
        int i = 0;
        // 处理 @Param 注解的参数
        for (String name : paramNames) {
            param.put(name, args[i++]);
        }
        // 为参数添加 param1, param2 等键
        if (paramNames.size() < args.length) {
            for (int j = paramNames.size(); j < args.length; j++) {
                param.put("param" + String.valueOf(j + 1), args[j]);
            }
        }
        return param;
    }
}
步骤 2:SqlSession 委托 Executor 执行查询
// DefaultSqlSession.java
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
        // 根据 statement ID 获取 MappedStatement
        MappedStatement ms = configuration.getMappedStatement(statement);
        
        // 委托 Executor 执行查询
        return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}

// 处理集合参数
private Object wrapCollection(final Object object) {
    if (object instanceof Collection) {
        StrictMap<Object> map = new StrictMap<>();
        map.put("collection", object);
        if (object instanceof List) {
            map.put("list", object);
        }
        return map;
    } else if (object != null && object.getClass().isArray()) {
        StrictMap<Object> map = new StrictMap<>();
        map.put("array", object);
        return map;
    }
    return object;
}
步骤 3:Executor 执行查询(以 SimpleExecutor 为例)
// BaseExecutor.java
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    // 获取 BoundSql(包含解析后的 SQL 和参数映射信息)
    BoundSql boundSql = ms.getBoundSql(parameter);
    
    // 创建缓存键(基于 SQL、参数、RowBounds 等)
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    
    // 执行查询(可能从缓存获取)
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}

@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    
    // 如果已关闭,抛出异常
    if (closed) {
        throw new ExecutorException("Executor was closed.");
    }
    
    // 先清空本地缓存(针对 select 语句,一级缓存会在查询前清空)
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
        clearLocalCache();
    }
    
    List<E> list;
    try {
        queryStack++;
        
        // 从本地缓存获取结果
        list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
        
        if (list != null) {
            // 处理存储过程的输出参数
            handleLocallyCachedOutputParameters(ms, key, parameter);
        } else {
            // 本地缓存未命中,执行数据库查询
            list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
        }
    } finally {
        queryStack--;
    }
    
    if (queryStack == 0) {
        // 延迟加载队列处理
        for (DeferredLoad deferredLoad : deferredLoads) {
            deferredLoad.load();
        }
        // 清空延迟加载队列
        deferredLoads.clear();
        
        // 一级缓存的作用域是 session,默认情况下,select 语句执行后会清空本地缓存
        if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
            clearLocalCache();
        }
    }
    
    return list;
}

// 从数据库查询
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    
    // 先在缓存中放入占位符,避免递归查询
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    
    try {
        // 调用子类的 doQuery 方法执行实际查询
        list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
        // 移除占位符
        localCache.removeObject(key);
    }
    
    // 将查询结果放入缓存
    localCache.putObject(key, list);
    
    // 处理存储过程的输出参数
    if (ms.getStatementType() == StatementType.CALLABLE) {
        localOutputParameterCache.putObject(key, parameter);
    }
    
    return list;
}

// SimpleExecutor.java
@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(路由到实际的 StatementHandler 实现)
        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
        
        // 准备 Statement
        stmt = prepareStatement(handler, ms.getStatementLog());
        
        // 执行查询
        return handler.query(stmt, resultHandler);
    } finally {
        // 关闭 Statement
        closeStatement(stmt);
    }
}

// 准备 Statement
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    // 获取数据库连接
    Connection connection = getConnection(statementLog);
    
    // 准备 Statement
    stmt = handler.prepare(connection, transaction.getTimeout());
    
    // 设置参数
    handler.parameterize(stmt);
    
    return stmt;
}
步骤 4:创建 StatementHandler(RoutingStatementHandler)
// Configuration.java
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    // 创建 StatementHandler(实际创建的是 RoutingStatementHandler)
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    
    // 应用插件(如果有)
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    
    return statementHandler;
}

// RoutingStatementHandler.java
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    // 根据 StatementType 选择实际的 StatementHandler 实现
    switch (ms.getStatementType()) {
        case STATEMENT:
            delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        case PREPARED:
            // 对于预编译语句,使用 PreparedStatementHandler
            delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        case CALLABLE:
            delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
            break;
        default:
            throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }
}
步骤 5:StatementHandler 准备 Statement
// BaseStatementHandler.java
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    
    try {
        // 实例化 Statement
        statement = instantiateStatement(connection);
        
        // 设置超时时间
        setStatementTimeout(statement, transactionTimeout);
        
        // 设置 fetchSize
        setFetchSize(statement);
        
        return statement;
    } catch (SQLException e) {
        closeStatement(statement);
        throw e;
    } catch (Exception e) {
        closeStatement(statement);
        throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
    }
}

// PreparedStatementHandler.java
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    
    // 获取主键生成策略
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
        String[] keyColumnNames = mappedStatement.getKeyColumns();
        if (keyColumnNames == null) {
            // 没有指定主键列,使用 JDBC 3.0 规范的方法获取自增主键
            return connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
        } else {
            // 指定了主键列,使用指定的列获取自增主键
            return connection.prepareStatement(sql, keyColumnNames);
        }
    } else if (mappedStatement.getResultSetType() != null) {
        // 设置结果集类型
        return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
        // 默认情况,创建预编译语句
        return connection.prepareStatement(sql);
    }
}
步骤 6:ParameterHandler 设置参数
// BaseStatementHandler.java
@Override
public void parameterize(Statement statement) throws SQLException {
    // 委托 ParameterHandler 设置参数
    parameterHandler.setParameters((PreparedStatement) statement);
}

// DefaultParameterHandler.java
@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();
                
                // 处理动态参数(如 _parameter、_databaseId)
                if (boundSql.hasAdditionalParameter(propertyName)) {
                    value = boundSql.getAdditionalParameter(propertyName);
                }
                // 处理参数为 null 的情况
                else if (parameterObject == null) {
                    value = null;
                }
                // 处理参数为基本类型的情况
                else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                    value = parameterObject;
                }
                // 处理参数为对象或 Map 的情况
                else {
                    MetaObject metaObject = configuration.newMetaObject(parameterObject);
                    value = metaObject.getValue(propertyName);
                }
                
                // 获取类型处理器
                TypeHandler typeHandler = parameterMapping.getTypeHandler();
                JdbcType jdbcType = parameterMapping.getJdbcType();
                
                // 处理 jdbcType 为 null 的情况
                if (value == null && jdbcType == null) {
                    jdbcType = configuration.getJdbcTypeForNull();
                }
                
                try {
                    // 设置参数(核心:类型处理器将 Java 对象转换为 JDBC 类型)
                    typeHandler.setParameter(ps, i + 1, value, jdbcType);
                } catch (TypeException e) {
                    throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
                } catch (SQLException e) {
                    throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
                }
            }
        }
    }
}
步骤 7:StatementHandler 执行查询
// PreparedStatementHandler.java
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
    // 转换为 PreparedStatement
    PreparedStatement ps = (PreparedStatement) statement;
    
    // 执行 SQL
    ps.execute();
    
    // 委托 ResultSetHandler 处理结果集
    return resultSetHandler.handleResultSets(ps);
}
步骤 8:ResultSetHandler 处理结果集
// DefaultResultSetHandler.java
@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;
    
    // 获取第一个结果集
    ResultSet rs = getFirstResultSet(stmt);
    
    // 获取结果映射列表
    List<ResultMap> resultMaps = mappedStatement.getResultMaps();
    
    int resultMapCount = resultMaps.size();
    
    // 验证结果映射数量
    validateResultMapsCount(rs, resultMapCount);
    
    // 处理所有结果集
    while (rs != null && resultMapCount > resultSetCount) {
        ResultMap resultMap = resultMaps.get(resultSetCount);
        
        // 处理单个结果集
        handleResultSet(rs, resultMap, multipleResults, null);
        
        // 获取下一个结果集(适用于存储过程返回多个结果集的情况)
        rs = getNextResultSet(stmt);
        
        // 清理资源
        cleanUpAfterHandlingResultSet();
        
        resultSetCount++;
    }
    
    // 处理结果集映射
    String[] resultSets = mappedStatement.getResultSets();
    if (resultSets != null) {
        while (rs != null && resultSetCount < resultSets.length) {
            // 处理命名结果集
            ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
            if (parentMapping != null) {
                String nestedResultMapId = parentMapping.getNestedResultMapId();
                ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
                handleResultSet(rs, resultMap, null, parentMapping);
            }
            rs = getNextResultSet(stmt);
            cleanUpAfterHandlingResultSet();
            resultSetCount++;
        }
    }
    
    // 处理单个结果集的情况,将其展开为列表
    return collapseSingleResultList(multipleResults);
}

// 处理单个结果集
private void handleResultSet(ResultSet rs, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
    try {
        if (parentMapping != null) {
            // 处理嵌套结果集
            handleRowValues(rs, resultMap, null, RowBounds.DEFAULT, parentMapping);
        } else {
            // 处理普通结果集
            if (resultHandler == null) {
                // 创建默认结果处理器
                DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
                
                // 处理行值
                handleRowValues(rs, resultMap, defaultResultHandler, rowBounds, null);
                
                // 将结果添加到多个结果列表中
                multipleResults.add(defaultResultHandler.getResultList());
            } else {
                // 使用用户提供的结果处理器
                handleRowValues(rs, resultMap, resultHandler, rowBounds, null);
            }
        }
    } finally {
        // 关闭结果集
        closeResultSet(rs);
    }
}

// 处理行值
private void handleRowValues(ResultSet rs, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
    if (resultMap.hasNestedResultMaps()) {
        // 处理包含嵌套结果映射的情况
        ensureNoRowBounds();
        checkResultHandler();
        handleRowValuesForNestedResultMap(rs, resultMap, resultHandler, rowBounds, parentMapping);
    } else {
        // 处理简单结果映射的情况
        handleRowValuesForSimpleResultMap(rs, resultMap, resultHandler, rowBounds);
    }
}

// 处理简单结果映射的行值
private void handleRowValuesForSimpleResultMap(ResultSet rs, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds) throws SQLException {
    DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
    
    // 跳过分页偏移量
    skipRows(rs, rowBounds.getOffset());
    
    // 处理行数据
    while (shouldProcessMoreRows(resultContext, rowBounds) && rs.next()) {
        // 获取判别式结果映射(用于动态结果映射)
        ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rs, resultMap, null);
        
        // 获取行值(创建结果对象并填充数据)
        Object rowValue = getRowValue(rs, discriminatedResultMap);
        
        // 将行值添加到结果上下文中
        resultContext.nextResultObject(rowValue);
        
        // 如果有结果处理器,调用它处理结果
        if (resultHandler != null) {
            resultHandler.handleResult(resultContext);
        }
    }
}

// 获取行值(创建结果对象并填充数据)
private Object getRowValue(ResultSet rs, ResultMap resultMap) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    
    // 创建结果对象
    Object rowValue = createResultObject(rs, resultMap, lazyLoader, null);
    
    if (rowValue != null && !resultMap.isPrimitive()) {
        // 创建元对象
        MetaObject metaObject = configuration.newMetaObject(rowValue);
        
        // 标记是否找到值
        boolean foundValues = this.useConstructorMappings;
        
        // 处理自动映射
        if (shouldApplyAutomaticMappings(resultMap, false)) {
            foundValues = applyAutomaticMappings(rs, resultMap, metaObject, null) || foundValues;
        }
        
        // 处理手动映射
        foundValues = applyPropertyMappings(rs, resultMap, metaObject, lazyLoader, null) || foundValues;
        
        // 如果没有找到任何值且需要非空结果,则返回 null
        foundValues = lazyLoader.size() > 0 || foundValues;
        rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    
    return rowValue;
}

// 创建结果对象
private Object createResultObject(ResultSet rs, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    this.useConstructorMappings = false; // 重置构造函数映射标志
    
    // 获取结果类型
    final Class<?> resultType = resultMap.getType();
    
    // 创建元对象处理器
    final List<Class<?>> constructorArgTypes = new ArrayList<>();
    final List<Object> constructorArgs = new ArrayList<>();
    
    // 创建结果对象
    Object resultObject = createResultObject(rs, resultType, constructorArgTypes, constructorArgs, columnPrefix);
    
    // 如果结果类型不是基本类型
    if (resultObject != null && !resultType.isInterface()) {
        // 检查是否有构造函数映射
        if (shouldApplyAutomaticMappings(resultMap, true)) {
            // 应用自动映射
            applyAutomaticMappings(rs, resultMap, configuration.newMetaObject(resultObject), columnPrefix);
        }
        
        // 应用属性映射
        applyPropertyMappings(rs, resultMap, configuration.newMetaObject(resultObject), lazyLoader, columnPrefix);
    }
    
    // 标记使用了构造函数映射
    this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty();
    
    return resultObject;
}

网站公告

今日签到

点亮在社区的每一天
去签到