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

news2025/6/5 14:40:14

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

  • 一、Mapper 代理对象的创建:sqlSession.getMapper(UserMapper.class)
  • 二、接口方法的执行:mapper.selectUser("coderzpw", 18)
    • 2.1 四大核心组件解析
      • 2.1.1 Executor(执行器):流程控制核心
      • 2.1.2 StatementHandler(语句处理器):JDBC 操作封装
      • 2.1.3 ParameterHandler(参数处理器):参数解析与绑定
      • 2.1.4 ResultSetHandler(结果集处理器):对象映射引擎
    • 2.2 源码解析-完整调用链路:从 Mapper 方法到结果集的全流程
      • 2.2.1 调用链路步骤分解
      • 2.2.2 关键源码串联(MyBatis 3.4.6 版本)
        • 步骤 1:Mapper 代理对象处理方法调用
        • 步骤 2:SqlSession 委托 Executor 执行查询
        • 步骤 3:Executor 执行查询(以 SimpleExecutor 为例)
        • 步骤 4:创建 StatementHandler(RoutingStatementHandler)
        • 步骤 5:StatementHandler 准备 Statement
        • 步骤 6:ParameterHandler 设置参数
        • 步骤 7:StatementHandler 执行查询
        • 步骤 8:ResultSetHandler 处理结果集

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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2397455.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Form Wave(表单label波动效果)

&#x1f4c5; 我们继续 50 个小项目挑战&#xff01;—— FormWave组件 仓库地址&#xff1a;https://github.com/SunACong/50-vue-projects 项目预览地址&#xff1a;https://50-vue-projects.vercel.app/ &#x1f3af; 组件目标 构建一个美观、动态的登录表单&#xff0…

双目相机深度的误差分析(基线长度和相机焦距的选择)

全文基于针孔模型和基线水平放置来讨论 影响双目计算深度的因素&#xff1a; 1、基线长度&#xff1a;两台相机光心之间距离2、相机焦距&#xff08;像素&#xff09;&#xff1a; f x f_x fx​&#xff08;或 f y f_y fy​&#xff09;为焦距 f f f和一个缩放比例的乘积。在…

Pytorch Geometric官方例程pytorch_geometric/examples/link_pred.py环境安装教程及图数据集制作

最近需要训练图卷积神经网络&#xff08;Graph Convolution Neural Network, GCNN&#xff09;&#xff0c;在配置GCNN环境上总结了一些经验。 我觉得对于初学者而言&#xff0c;图神经网络的训练会有2个难点&#xff1a; ①环境配置 ②数据集制作 一、环境配置 我最初光想…

React---day6、7

6、组件之间进行数据传递 **6.1 父传子&#xff1a;**props传递属性 父组件&#xff1a; <div><ChildCpn name"蒋乙菥" age"18" height"1,88" /> </div>子组件&#xff1a; export class ChildCpn extends React.Component…

hook组件-useEffect、useRef

hook组件-useEffect、useRef useEffect 用法及执行机制 WillMount -> render -> DidMount ShouldUpdate -> WillUpdate -> render -> DidUpdate WillUnmount(只有这个安全) WillReceiveProps useEffect(callback) 默认所有依赖都更新useEffect(callback, [])&am…

随机游动算法解决kSAT问题

input&#xff1a;n个变量的k-CNF公式 ouput&#xff1a;该公式的一组满足赋值或宣布没有满足赋值 算法步骤&#xff1a; 随机均匀地初始化赋值 a ∈ { 0 , 1 } n a\in\{0,1\}^n a∈{0,1}n.重复t次&#xff08;后面会估计这个t&#xff09;&#xff1a; a. 如果在当前赋值下…

《Discuz! X3.5开发从入门到生态共建》第1章 Discuz! 的前世今生-优雅草卓伊凡

《Discuz! X3.5开发从入门到生态共建》第1章 Discuz! 的前世今生-优雅草卓伊凡 第一节 从康盛创想到腾讯收购&#xff1a;PC时代的辉煌 1.1 Discuz! 的诞生&#xff1a;康盛创想的开源梦想 2001年&#xff0c;中国互联网正处于萌芽阶段&#xff0c;个人网站和论坛开始兴起。…

笔试强训:Day6

一、小红的口罩&#xff08;贪心优先级队列&#xff09; 登录—专业IT笔试面试备考平台_牛客网 #include<iostream> #include<queue> #include<vector> using namespace std; int n,k; int main(){//用一个小根堆 每次使用不舒适度最小的cin>>n>&…

谷歌Stitch:AI赋能UI设计,免费高效新利器

在AI技术日新月异的今天&#xff0c;各大科技巨头都在不断刷新我们对智能工具的认知。最近&#xff0c;谷歌在其年度I/O开发者大会期间&#xff0c;除了那些聚光灯下的重磅发布&#xff0c;还悄然上线了一款令人惊喜的AI工具——Stitch。这是一款全新的、完全免费的AI驱动UI&am…

运营商地址和ip属地一样吗?怎么样更改ip属地地址

‌在互联网时代&#xff0c;IP属地和运营商地址是两个经常被提及的概念&#xff0c;但它们是否相同&#xff1f;如何更改IP属地地址&#xff1f;这些问题困扰着许多网民。本文将深入探讨这两个概念的区别&#xff0c;并详细介绍更改IP属地地址的方法。 一、运营商地址和IP属地一…

在QT中,利用charts库绘制FFT图形

第1章 添加charts库 1.1 .pro工程添加chart库 1.1.1 在.pro工程里面添加charts库 1.1.2 在需要使用的地方添加这两个库函数&#xff0c;顺序一点不要搞错&#xff0c;先添加.pro&#xff0c;否则编译器会找不到这两个.h文件。 第2章 Charts关键绘图函数 2.1 QChart 类 QChart 是…

流媒体协议分析:流媒体传输的基石

在流媒体传输过程中&#xff0c;协议的选择至关重要&#xff0c;它决定了数据如何封装、传输和解析&#xff0c;直接影响着视频的播放质量和用户体验。本文将深入分析几种常见的流媒体传输协议&#xff0c;探讨它们的特点、应用场景及优缺点。 协议分类概述 流媒体传输协议根据…

vscode中让文件夹一直保持展开不折叠

vscode中让文件夹一直保持展开不折叠 问题 很多小伙伴使用vscode发现空文件夹会折叠显示, 让人看起来非常难受, 如下图 解决办法 首先打开设置->setting, 搜索compact Folders, 去掉勾选即可, 如下图所示 效果如下 看起来非常爽 ! ! !

JAVA-springboot整合Mybatis

SpringBoot从入门到精通-第15章 MyBatis框架 学习MyBatis心路历程 2022年学习java基础时候&#xff0c;想着怎么使用java代码操作数据库&#xff0c;咨询了项目上开发W同事&#xff0c;没有引用框架&#xff0c;操作数据库很麻烦&#xff0c;就帮我写好多行代码&#xff0c;就…

深度学习pycharm debug

深度学习中&#xff0c;Debug 是定位并解决代码逻辑错误&#xff08;如张量维度不匹配&#xff09;、训练异常&#xff08;如 Loss 波动&#xff09;、数据问题&#xff08;如标签错误&#xff09;的关键手段&#xff0c;通过打印维度、可视化梯度等方法确保模型正常运行、优化…

MicroPython+L298N+ESP32控制电机转速

要使用MicroPython控制L298N电机驱动板来控制电机的转速&#xff0c;你可以通过PWM&#xff08;脉冲宽度调制&#xff09;信号来调节电机速度。L298N是一个双H桥驱动器&#xff0c;可以同时控制两个电机的正反转和速度。 硬件准备&#xff1a; 1. L298N 电机控制板 2. ESP32…

在部署了一台mysql5.7的机器上部署mysql8.0.35

在已部署 MySQL 5.7 的机器上部署 MySQL 8.0.35 的完整指南 在同一台服务器上部署多个 MySQL 版本需要谨慎规划&#xff0c;避免端口冲突和数据混淆。以下是详细的部署步骤&#xff1a; 一、规划配置 端口分配 MySQL 5.7&#xff1a;使用默认端口 3306MySQL 8.0.35&#xff1…

QT入门学习(一)---新建工程与、信号与槽

一: 新建QT项目 二:QT文件构成 2.1 first.pro 项目管理文件&#xff0c;下面来看代码解析 QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11TARGET main# The following define makes your compiler emit warnings if you use # any Qt feature …

UE5.4.4+Rider2024.3.7开发环境配置

文章目录 一、UE5安装 安装有两种方式一种的源码编译安装、一种是EPIC安装&#xff0c;推荐后者&#xff0c;只需要注册一个EPIC账号就可以一键安装。 二、C环境安装 1.下载VisualStudioSetup 下载链接如下下载 Visual Studio Tools - 免费安装 Windows、Mac、Linux 选择社…

Windows环境下PHP,在PowerShell控制台输出中文乱码

解决方法&#xff1a; 以管理员运行PowerShell , 输入&#xff1a; chcp 65001 重启控制台&#xff1b;然后就正常输出中文&#xff1b;