马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
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
关键逻辑:将方法参数(如 name 和 age)映射到 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) 调用,执行时通过署理对象触发 MapperProxy 的 invoke 方法,进而调用 MapperMethod 的 execute 方法,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 组件)
- │
- ├─ 【Executor(SimpleExecutor)】
- │ ├─ 创建 StatementHandler(PreparedStatementHandler)
- │ ├─ 调用 handler.prepare() 创建 PreparedStatement(含预编译 SQL)
- │ ├─ 调用 handler.parameterize() 触发 ParameterHandler 设置参数
- │ └─ 调用 handler.query() 执行 SQL,获取 ResultSet
- │
- ├─ 【StatementHandler(PreparedStatementHandler)】
- │ ├─ instantiateStatement() 创建 PreparedStatement(SQL: "select * from user where name = ? and age > ?")
- │ ├─ setParameters() 委托 ParameterHandler 绑定参数(name=? 对应 "张三",age=? 对应 20)
- │ └─ execute() 执行查询,返回 ResultSet 给 ResultSetHandler
- │
- ├─ 【ParameterHandler(DefaultParameterHandler)】
- │ └─ setParameters() 遍历参数映射,通过 TypeHandler 转换并设置到 PreparedStatement
- │
- └─ 【ResultSetHandler(DefaultResultSetHandler)】
- ├─ 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;
- }
复制代码 |