中国建设教育协会网站培训中心,台州网站建设设计,一站式外贸服务平台,网络营销推广的劣势1. 学习目标确认1.0 第5篇思考题解答在深入学习StatementHandler语句处理器之前#xff0c;让我们先回顾并解答第5篇中提出的思考题#xff0c;这将帮助我们更好地理解StatementHandler在整个架构中的作用。思考题1#xff1a;为什么MyBatis要设计多种Executor类型#xff…1. 学习目标确认1.0 第5篇思考题解答在深入学习StatementHandler语句处理器之前让我们先回顾并解答第5篇中提出的思考题这将帮助我们更好地理解StatementHandler在整个架构中的作用。思考题1为什么MyBatis要设计多种Executor类型它们各自的优势是什么答案要点SimpleExecutor简单可靠每次创建新Statement适合大多数场景资源管理清晰ReuseExecutor重用Statement对象减少创建开销适合重复执行相同SQL的场景BatchExecutor批量执行多个SQL大幅减少数据库交互次数适合批量数据操作CachingExecutor装饰器模式实现二级缓存提升查询性能适合读多写少的场景设计理念不同场景有不同需求通过多种执行器满足不同性能要求StatementHandler的作用StatementHandler是Executor的核心组件负责具体的SQL语句预处理、参数设置和结果处理。思考题2BaseExecutor的模板方法模式是如何实现的这种设计有什么优势答案要点模板方法定义BaseExecutor定义了query()和update()的标准流程包含缓存检查、错误处理、延迟加载等通用逻辑抽象方法实现子类只需实现doQuery()和doUpdate()等具体方法专注于自己的核心逻辑优势体现代码复用、逻辑统一、扩展性强、维护性好一级缓存管理BaseExecutor统一管理一级缓存的生命周期和策略与StatementHandler的协作BaseExecutor通过StatementHandler执行具体的SQL操作StatementHandler是模板方法中具体实现的关键组件。思考题3CachingExecutor的装饰器模式是如何工作的与一级缓存有什么区别答案要点装饰器模式CachingExecutor包装其他执行器在不修改原执行器的基础上添加缓存功能二级缓存特点跨SqlSession共享支持事务性配置更灵活一级缓存特点SqlSession级别自动管理生命周期与SqlSession绑定事务缓存管理通过TransactionalCacheManager管理缓存的事务性确保数据一致性StatementHandler的执行CachingExecutor在缓存未命中时委托给被装饰的执行器最终通过StatementHandler执行SQL。思考题4在什么场景下应该使用BatchExecutor使用时需要注意什么问题答案要点适用场景批量插入、更新、删除大量数据的批量处理数据迁移等性能优势减少网络往返次数提升批量操作的吞吐量注意事项必须调用flushStatements()才能执行事务边界管理内存使用控制使用限制只支持相同类型的SQL批量操作需要手动管理批量提交StatementHandler的批量处理BatchExecutor通过StatementHandler的batch()方法将多个操作添加到批量队列中。1.1 本篇学习目标通过本文你将能够深入理解StatementHandler语句处理器的设计思想和职责分工掌握RoutingStatementHandler的路由机制和选择策略理解PreparedStatementHandler、CallableStatementHandler、SimpleStatementHandler的具体实现掌握SQL语句的预处理、参数设置和结果处理流程了解StatementHandler与ParameterHandler、ResultSetHandler的协作关系具备自定义StatementHandler扩展开发的能力2. StatementHandler语句处理器体系总览2.1 语句处理器继承关系图delegates to«interface»StatementHandlerprepare(Connection, Integer) : Statementparameterize(Statement) : voidbatch(Statement) : voidupdate(Statement) : intquery(Statement, ResultHandler) : ListEqueryCursor(Statement) : CursorEgetBoundSql() : BoundSqlgetParameterHandler() : ParameterHandlergetResultSetHandler() : ResultSetHandler«abstract»BaseStatementHandler#configuration Configuration#executor Executor#mappedStatement MappedStatement#parameterObject Object#rowBounds RowBounds#resultHandler ResultHandler#boundSql BoundSql#parameterHandler ParameterHandler#resultSetHandler ResultSetHandler#prepareStatement(Connection, String) : PreparedStatement#instantiateStatement(Connection) : StatementRoutingStatementHandler-delegate StatementHandlerRoutingStatementHandler(Executor, MappedStatement, Object, RowBounds, ResultHandler, BoundSql)prepare(Connection, Integer) : Statementparameterize(Statement) : voidbatch(Statement) : voidupdate(Statement) : intquery(Statement, ResultHandler) : ListEqueryCursor(Statement) : CursorEgetBoundSql() : BoundSqlgetParameterHandler() : ParameterHandlergetResultSetHandler() : ResultSetHandlerPreparedStatementHandler-preparedStatement PreparedStatementprepare(Connection, Integer) : PreparedStatementparameterize(PreparedStatement) : voidbatch(PreparedStatement) : voidupdate(PreparedStatement) : intquery(PreparedStatement, ResultHandler) : ListEqueryCursor(PreparedStatement) : CursorECallableStatementHandler-callableStatement CallableStatementprepare(Connection, Integer) : CallableStatementparameterize(CallableStatement) : voidbatch(CallableStatement) : voidupdate(CallableStatement) : intquery(CallableStatement, ResultHandler) : ListEqueryCursor(CallableStatement) : CursorESimpleStatementHandler-statement Statementprepare(Connection, Integer) : Statementparameterize(Statement) : voidbatch(Statement) : voidupdate(Statement) : intquery(Statement, ResultHandler) : ListEqueryCursor(Statement) : CursorE2.2 语句处理器职责分工处理器类型 核心职责 适用场景 特点RoutingStatementHandler 路由选择具体的StatementHandler 所有场景的入口 根据StatementType路由到具体实现PreparedStatementHandler 处理PreparedStatement 参数化查询 支持参数绑定防止SQL注入CallableStatementHandler 处理CallableStatement 存储过程调用 支持输入输出参数SimpleStatementHandler 处理Statement 静态SQL 简单直接无参数绑定2.3 语句处理器协作关系DatabaseResultSetHandlerParameterHandlerStatementHandlerExecutorDatabaseResultSetHandlerParameterHandlerStatementHandlerExecutornewStatementHandler(ms, param, rowBounds, handler, boundSql)prepare(connection, timeout)create StatementStatementparameterize(statement)set parametersparameters setexecute query/updateResultSet/UpdateCounthandleResultSets(statement)ListObjectresults3. RoutingStatementHandler路由处理器3.1 核心实现RoutingStatementHandler是StatementHandler的入口负责根据StatementType路由到具体的处理器package org.apache.ibatis.executor.statement;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.executor.resultset.ResultSetHandler;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.mapping.StatementType;import org.apache.ibatis.plugin.Interceptor;import org.apache.ibatis.plugin.Intercepts;import org.apache.ibatis.plugin.Invocation;import org.apache.ibatis.plugin.Plugin;import org.apache.ibatis.plugin.Signature;import org.apache.ibatis.reflection.factory.ObjectFactory;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import java.sql.Connection;import java.sql.Statement;import java.util.List;/*** 路由语句处理器根据StatementType路由到具体的StatementHandler实现* 这是StatementHandler的入口采用策略模式*/Intercepts({Signature(type StatementHandler.class, method prepare, args {Connection.class, Integer.class})})public class RoutingStatementHandler implements StatementHandler {private final StatementHandler delegate;/*** 构造方法根据StatementType创建对应的StatementHandler*/public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {// 根据StatementType选择具体的StatementHandler实现switch (ms.getStatementType()) {case STATEMENT:delegate new SimpleStatementHandler(executor, ms, parameterObject, rowBounds, resultHandler, boundSql);break;case PREPARED:delegate new PreparedStatementHandler(executor, ms, parameterObject, rowBounds, resultHandler, boundSql);break;case CALLABLE:delegate new CallableStatementHandler(executor, ms, parameterObject, rowBounds, resultHandler, boundSql);break;default:throw new ExecutorException(Unknown statement type: ms.getStatementType());}}Overridepublic Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {return delegate.prepare(connection, transactionTimeout);}Overridepublic void parameterize(Statement statement) throws SQLException {delegate.parameterize(statement);}Overridepublic void batch(Statement statement) throws SQLException {delegate.batch(statement);}Overridepublic int update(Statement statement) throws SQLException {return delegate.update(statement);}Overridepublic E ListE query(Statement statement, ResultHandler resultHandler) throws SQLException {return delegate.query(statement, resultHandler);}Overridepublic E CursorE queryCursor(Statement statement) throws SQLException {return delegate.queryCursor(statement);}Overridepublic BoundSql getBoundSql() {return delegate.getBoundSql();}Overridepublic ParameterHandler getParameterHandler() {return delegate.getParameterHandler();}Overridepublic ResultSetHandler getResultSetHandler() {return delegate.getResultSetHandler();}Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}}3.2 路由策略RoutingStatementHandler根据MappedStatement中的StatementType进行路由// StatementType枚举定义public enum StatementType {STATEMENT, // 对应Statement静态SQLPREPARED, // 对应PreparedStatement参数化SQLCALLABLE // 对应CallableStatement存储过程}// 路由逻辑switch (ms.getStatementType()) {case STATEMENT:// 使用SimpleStatementHandler处理静态SQLdelegate new SimpleStatementHandler(...);break;case PREPARED:// 使用PreparedStatementHandler处理参数化SQL默认delegate new PreparedStatementHandler(...);break;case CALLABLE:// 使用CallableStatementHandler处理存储过程delegate new CallableStatementHandler(...);break;}4. BaseStatementHandler抽象基类4.1 核心实现BaseStatementHandler是所有具体StatementHandler的基类提供通用的功能和属性package org.apache.ibatis.executor.statement;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.executor.parameter.ParameterHandler;import org.apache.ibatis.executor.resultset.ResultSetHandler;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.mapping.ParameterMapping;import org.apache.ibatis.mapping.ParameterMode;import org.apache.ibatis.mapping.StatementType;import org.apache.ibatis.reflection.MetaObject;import org.apache.ibatis.reflection.factory.ObjectFactory;import org.apache.ibatis.session.Configuration;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import org.apache.ibatis.type.TypeHandlerRegistry;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;import java.sql.Statement;import java.util.List;/*** 语句处理器抽象基类* 提供StatementHandler的通用功能和属性管理*/public abstract class BaseStatementHandler implements StatementHandler {// MyBatis全局配置对象protected final Configuration configuration;// 执行器用于执行延迟加载等操作protected final Executor executor;// SQL映射语句包含SQL和结果映射信息protected final MappedStatement mappedStatement;// 参数对象传递给SQL的参数protected final Object parameterObject;// 分页参数protected final RowBounds rowBounds;// 结果处理器用于自定义结果处理protected final ResultHandler resultHandler;// 绑定的SQL对象包含最终执行的SQL和参数映射protected final BoundSql boundSql;// 参数处理器负责设置SQL参数protected final ParameterHandler parameterHandler;// 结果集处理器负责处理查询结果protected final ResultSetHandler resultSetHandler;/*** 构造方法*/public BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {this.configuration mappedStatement.getConfiguration();this.executor executor;this.mappedStatement mappedStatement;this.parameterObject parameterObject;this.rowBounds rowBounds;this.resultHandler resultHandler;this.boundSql boundSql;// 创建参数处理器this.parameterHandler configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);// 创建结果集处理器this.resultSetHandler configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);}/*** 准备Statement对象* 子类实现具体的Statement创建逻辑*/Overridepublic abstract Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;/*** 设置参数* 委托给ParameterHandler处理*/Overridepublic void parameterize(Statement statement) throws SQLException {parameterHandler.setParameters(statement);}/*** 批量操作* 委托给ParameterHandler处理*/Overridepublic void batch(Statement statement) throws SQLException {parameterHandler.batch(statement);}/*** 执行更新操作* 委托给具体的Statement执行*/Overridepublic int update(Statement statement) throws SQLException {PreparedStatement ps (PreparedStatement) statement;ps.execute();int rows ps.getUpdateCount();Object parameterObject boundSql.getParameterObject();KeyGenerator keyGenerator mappedStatement.getKeyGenerator();keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);return rows;}/*** 执行查询操作* 委托给ResultSetHandler处理结果集*/Overridepublic E ListE query(Statement statement, ResultHandler resultHandler) throws SQLException {PreparedStatement ps (PreparedStatement) statement;ps.execute();return resultSetHandler.handleResultSets(ps);}/*** 执行游标查询* 委托给ResultSetHandler处理*/Overridepublic E CursorE queryCursor(Statement statement) throws SQLException {PreparedStatement ps (PreparedStatement) statement;ps.execute();return resultSetHandler.handleCursorResultSets(ps);}Overridepublic BoundSql getBoundSql() {return boundSql;}Overridepublic ParameterHandler getParameterHandler() {return parameterHandler;}Overridepublic ResultSetHandler getResultSetHandler() {return resultSetHandler;}/*** 准备PreparedStatement对象* 子类可以调用此方法创建PreparedStatement*/protected PreparedStatement prepareStatement(Connection connection, String sql) throws SQLException {String mappedStatementId mappedStatement.getId();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);} else {return connection.prepareStatement(sql);}}/*** 实例化Statement对象* 子类实现具体的Statement创建逻辑*/protected abstract Statement instantiateStatement(Connection connection) throws SQLException;}4.2 组件协作BaseStatementHandler通过组合模式管理ParameterHandler和ResultSetHandler// 组件创建this.parameterHandler configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);this.resultSetHandler configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);// 委托执行Overridepublic void parameterize(Statement statement) throws SQLException {parameterHandler.setParameters(statement); // 委托给ParameterHandler}Overridepublic E ListE query(Statement statement, ResultHandler resultHandler) throws SQLException {PreparedStatement ps (PreparedStatement) statement;ps.execute();return resultSetHandler.handleResultSets(ps); // 委托给ResultSetHandler}5. PreparedStatementHandler预编译处理器5.1 核心实现PreparedStatementHandler是最常用的StatementHandler处理参数化的SQL语句package org.apache.ibatis.executor.statement;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.executor.parameter.ParameterHandler;import org.apache.ibatis.executor.resultset.ResultSetHandler;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;import java.sql.Statement;/*** 预编译语句处理器* 处理PreparedStatement支持参数绑定防止SQL注入* 这是MyBatis默认使用的StatementHandler*/public class PreparedStatementHandler extends BaseStatementHandler {/*** 构造方法*/public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {super(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);}/*** 准备PreparedStatement对象*/Overridepublic Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {ErrorContext.instance().sql(boundSql.getSql());PreparedStatement statement null;try {// 创建PreparedStatement对象statement instantiateStatement(connection);// 设置超时时间setStatementTimeout(statement, transactionTimeout);// 设置获取大小用于游标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);}}/*** 实例化PreparedStatement对象*/Overrideprotected Statement instantiateStatement(Connection connection) throws SQLException {String sql boundSql.getSql();// 根据KeyGenerator类型创建不同的PreparedStatementif (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);} else {// 普通PreparedStatementreturn connection.prepareStatement(sql);}}/*** 设置参数* 委托给ParameterHandler处理*/Overridepublic void parameterize(Statement statement) throws SQLException {parameterHandler.setParameters((PreparedStatement) statement);}/*** 批量操作*/Overridepublic void batch(Statement statement) throws SQLException {PreparedStatement ps (PreparedStatement) statement;ps.addBatch();}/*** 执行更新操作*/Overridepublic int update(Statement statement) throws SQLException {PreparedStatement ps (PreparedStatement) statement;ps.execute();int rows ps.getUpdateCount();Object parameterObject boundSql.getParameterObject();KeyGenerator keyGenerator mappedStatement.getKeyGenerator();// 处理主键生成keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);return rows;}/*** 执行查询操作*/Overridepublic E ListE query(Statement statement, ResultHandler resultHandler) throws SQLException {PreparedStatement ps (PreparedStatement) statement;ps.execute();return resultSetHandler.handleResultSets(ps);}/*** 执行游标查询*/Overridepublic E CursorE queryCursor(Statement statement) throws SQLException {PreparedStatement ps (PreparedStatement) statement;ps.execute();return resultSetHandler.handleCursorResultSets(ps);}/*** 设置Statement超时时间*/private void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException {Integer queryTimeout null;if (mappedStatement.getTimeout() ! null) {queryTimeout mappedStatement.getTimeout();} else if (configuration.getDefaultStatementTimeout() ! null) {queryTimeout configuration.getDefaultStatementTimeout();}if (queryTimeout ! null) {stmt.setQueryTimeout(queryTimeout);}StatementUtil.applyTransactionTimeout(stmt, transactionTimeout);}/*** 设置获取大小*/private void setFetchSize(Statement stmt) throws SQLException {Integer fetchSize mappedStatement.getFetchSize();if (fetchSize ! null) {stmt.setFetchSize(fetchSize);return;}Integer defaultFetchSize configuration.getDefaultFetchSize();if (defaultFetchSize ! null) {stmt.setFetchSize(defaultFetchSize);}}}5.2 优势特点安全性参数绑定使用PreparedStatement的参数绑定机制有效防止SQL注入类型安全通过ParameterHandler进行类型转换和参数设置性能优化SQL预编译SQL语句在数据库端预编译提升执行效率参数复用相同SQL结构的查询可以复用预编译的Statement功能丰富主键生成支持自动生成主键和获取生成的主键结果集控制支持结果集类型和并发模式设置超时控制支持查询超时和事务超时设置6. CallableStatementHandler存储过程处理器6.1 核心实现CallableStatementHandler专门处理存储过程调用package org.apache.ibatis.executor.statement;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.executor.resultset.ResultSetHandler;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import java.sql.CallableStatement;import java.sql.Connection;import java.sql.SQLException;import java.sql.Statement;/*** 存储过程语句处理器* 处理CallableStatement支持存储过程调用* 支持输入参数、输出参数和输入输出参数*/public class CallableStatementHandler extends BaseStatementHandler {/*** 构造方法*/public CallableStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {super(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);}/*** 准备CallableStatement对象*/Overridepublic Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {ErrorContext.instance().sql(boundSql.getSql());CallableStatement statement null;try {// 创建CallableStatement对象statement instantiateStatement(connection);// 设置超时时间setStatementTimeout(statement, transactionTimeout);// 设置获取大小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);}}/*** 实例化CallableStatement对象*/Overrideprotected Statement instantiateStatement(Connection connection) throws SQLException {String sql boundSql.getSql();// 创建CallableStatementif (mappedStatement.getResultSetType() ! null) {return connection.prepareCall(sql,mappedStatement.getResultSetType().getValue(),ResultSet.CONCUR_READ_ONLY);} else {return connection.prepareCall(sql);}}/*** 设置参数* 存储过程支持输入、输出和输入输出参数*/Overridepublic void parameterize(Statement statement) throws SQLException {// 注册输出参数registerOutputParameters((CallableStatement) statement);// 设置输入参数parameterHandler.setParameters((CallableStatement) statement);}/*** 批量操作* 存储过程通常不支持批量操作*/Overridepublic void batch(Statement statement) throws SQLException {CallableStatement cs (CallableStatement) statement;cs.addBatch();}/*** 执行更新操作*/Overridepublic int update(Statement statement) throws SQLException {CallableStatement cs (CallableStatement) statement;cs.execute();int rows cs.getUpdateCount();// 处理输出参数resultSetHandler.handleOutputParameters(cs);return rows;}/*** 执行查询操作*/Overridepublic E ListE query(Statement statement, ResultHandler resultHandler) throws SQLException {CallableStatement cs (CallableStatement) statement;cs.execute();ListE resultList resultSetHandler.handleResultSets(cs);// 处理输出参数resultSetHandler.handleOutputParameters(cs);return resultList;}/*** 执行游标查询*/Overridepublic E CursorE queryCursor(Statement statement) throws SQLException {CallableStatement cs (CallableStatement) statement;cs.execute();CursorE cursor resultSetHandler.handleCursorResultSets(cs);// 处理输出参数resultSetHandler.handleOutputParameters(cs);return cursor;}/*** 注册输出参数* 根据参数映射配置注册输出参数的类型*/private void registerOutputParameters(CallableStatement cs) throws SQLException {ListParameterMapping parameterMappings boundSql.getParameterMappings();for (int i 0; i parameterMappings.size(); i) {ParameterMapping parameterMapping parameterMappings.get(i);if (parameterMapping.getMode() ParameterMode.OUT || parameterMapping.getMode() ParameterMode.INOUT) {if (null ! parameterMapping.getJdbcType()) {if (parameterMapping.getNumericScale() ! null (parameterMapping.getJdbcType() JdbcType.NUMERIC || parameterMapping.getJdbcType() JdbcType.DECIMAL)) {cs.registerOutParameter(i 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale());} else {cs.registerOutParameter(i 1, parameterMapping.getJdbcType().TYPE_CODE);}} else {cs.registerOutParameter(i 1, parameterMapping.getJavaType());}}}}}6.2 存储过程特点参数支持输入参数传递数据给存储过程输出参数从存储过程获取数据输入输出参数既输入又输出的参数结果处理结果集存储过程可以返回多个结果集输出参数通过OUT参数返回数据返回值存储过程的执行状态7. SimpleStatementHandler简单处理器7.1 核心实现SimpleStatementHandler处理静态SQL语句package org.apache.ibatis.executor.statement;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.executor.resultset.ResultSetHandler;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import java.sql.Connection;import java.sql.SQLException;import java.sql.Statement;/*** 简单语句处理器* 处理Statement用于静态SQL语句* 不支持参数绑定适用于简单的静态SQL*/public class SimpleStatementHandler extends BaseStatementHandler {/*** 构造方法*/public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {super(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);}/*** 准备Statement对象*/Overridepublic Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {ErrorContext.instance().sql(boundSql.getSql());Statement statement null;try {// 创建Statement对象statement instantiateStatement(connection);// 设置超时时间setStatementTimeout(statement, transactionTimeout);// 设置获取大小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);}}/*** 实例化Statement对象*/Overrideprotected Statement instantiateStatement(Connection connection) throws SQLException {// 创建普通Statementif (mappedStatement.getResultSetType() ! null) {return connection.createStatement(mappedStatement.getResultSetType().getValue(),ResultSet.CONCUR_READ_ONLY);} else {return connection.createStatement();}}/*** 设置参数* Statement不支持参数绑定直接执行SQL*/Overridepublic void parameterize(Statement statement) throws SQLException {// Statement不支持参数化无需设置参数// 参数已经直接拼接到SQL中}/*** 批量操作*/Overridepublic void batch(Statement statement) throws SQLException {Statement stmt (Statement) statement;stmt.addBatch(boundSql.getSql());}/*** 执行更新操作*/Overridepublic int update(Statement statement) throws SQLException {Statement stmt (Statement) statement;stmt.execute(boundSql.getSql());int rows stmt.getUpdateCount();Object parameterObject boundSql.getParameterObject();KeyGenerator keyGenerator mappedStatement.getKeyGenerator();// 处理主键生成keyGenerator.processAfter(executor, mappedStatement, stmt, parameterObject);return rows;}/*** 执行查询操作*/Overridepublic E ListE query(Statement statement, ResultHandler resultHandler) throws SQLException {Statement stmt (Statement) statement;stmt.execute(boundSql.getSql());return resultSetHandler.handleResultSets(stmt);}/*** 执行游标查询*/Overridepublic E CursorE queryCursor(Statement statement) throws SQLException {Statement stmt (Statement) statement;stmt.execute(boundSql.getSql());return resultSetHandler.handleCursorResultSets(stmt);}}7.2 适用场景优点简单直接无需参数处理直接执行SQL性能开销小没有参数绑定和类型转换开销灵活性高支持任意复杂的静态SQL缺点SQL注入风险不支持参数绑定存在SQL注入风险类型不安全没有类型检查和转换维护困难参数直接拼接在SQL中不易维护适用场景DDL语句CREATE、ALTER、DROP等简单查询不需要参数的静态查询批量操作大量相同结构的操作8. 实践案例自定义StatementHandler8.1 性能监控StatementHandler让我们创建一个性能监控StatementHandler记录SQL执行时间package com.example.statement;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.executor.resultset.ResultSetHandler;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.plugin.Interceptor;import org.apache.ibatis.plugin.Intercepts;import org.apache.ibatis.plugin.Invocation;import org.apache.ibatis.plugin.Plugin;import org.apache.ibatis.plugin.Signature;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import java.sql.Statement;import java.util.List;import java.util.Properties;/*** 性能监控StatementHandler插件* 记录SQL执行时间和执行次数*/Intercepts({Signature(type org.apache.ibatis.executor.statement.StatementHandler.class,method query,args {Statement.class, ResultHandler.class}),Signature(type org.apache.ibatis.executor.statement.StatementHandler.class,method update,args {Statement.class})})public class PerformanceMonitorStatementHandler implements Interceptor {private long slowQueryThreshold 1000; // 慢查询阈值默认1秒private boolean enableStatistics true; // 是否启用统计Overridepublic Object intercept(Invocation invocation) throws Throwable {long startTime System.currentTimeMillis();String methodName invocation.getMethod().getName();try {// 执行原始方法Object result invocation.proceed();// 计算执行时间long endTime System.currentTimeMillis();long executionTime endTime - startTime;// 获取SQL信息org.apache.ibatis.executor.statement.StatementHandler statementHandler (org.apache.ibatis.executor.statement.StatementHandler) invocation.getTarget();BoundSql boundSql statementHandler.getBoundSql();String sql boundSql.getSql();// 记录执行信息recordExecution(methodName, sql, executionTime, result);return result;} catch (Throwable e) {// 记录异常信息long endTime System.currentTimeMillis();long executionTime endTime - startTime;recordException(invocation.getMethod().getName(), executionTime, e);throw e;}}/*** 记录执行信息*/private void recordExecution(String methodName, String sql, long executionTime, Object result) {// 慢查询检测if (executionTime slowQueryThreshold) {System.out.println(String.format(SLOW QUERY DETECTED: %s executed in %d ms,methodName, executionTime));System.out.println(SQL: sql);}// 统计信息if (enableStatistics) {System.out.println(String.format(SQL Execution: %s completed in %d ms,methodName, executionTime));// 记录结果信息if (query.equals(methodName) result instanceof List) {List? resultList (List?) result;System.out.println(Result count: resultList.size());} else if (update.equals(methodName)) {System.out.println(Affected rows: result);}}}/*** 记录异常信息*/private void recordException(String methodName, long executionTime, Throwable e) {System.err.println(String.format(SQL Execution ERROR: %s failed after %d ms,methodName, executionTime));System.err.println(Error: e.getMessage());}Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}Overridepublic void setProperties(Properties properties) {String threshold properties.getProperty(slowQueryThreshold);if (threshold ! null) {this.slowQueryThreshold Long.parseLong(threshold);}String statistics properties.getProperty(enableStatistics);if (statistics ! null) {this.enableStatistics Boolean.parseBoolean(statistics);}}}8.2 配置使用在mybatis-config.xml中配置插件configurationpluginsplugin interceptorcom.example.statement.PerformanceMonitorStatementHandlerproperty nameslowQueryThreshold value500/property nameenableStatistics valuetrue//plugin/plugins/configuration8.3 测试代码package com.example;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;/*** StatementHandler测试示例* 展示不同类型StatementHandler的使用*/public class StatementHandlerExample {public static void main(String[] args) throws Exception {// 加载MyBatis配置文件String resource mybatis-config.xml;InputStream inputStream Resources.getResourceAsStream(resource);SqlSessionFactory factory new SqlSessionFactoryBuilder().build(inputStream);// 测试不同类型的StatementHandlertestPreparedStatementHandler(factory);testSimpleStatementHandler(factory);testCallableStatementHandler(factory);}/*** 测试PreparedStatementHandler默认* 特点参数化SQL防止SQL注入*/private static void testPreparedStatementHandler(SqlSessionFactory factory) {System.out.println( 测试 PreparedStatementHandler );try (SqlSession session factory.openSession()) {UserMapper mapper session.getMapper(UserMapper.class);// 参数化查询System.out.println( 参数化查询);User user mapper.findById(1L);System.out.println(查询结果: user);// 参数化更新System.out.println( 参数化更新);user.setEmail(newemailexample.com);int updateCount mapper.updateUser(user);System.out.println(更新影响行数: updateCount);System.out.println(注意PreparedStatementHandler 是默认的处理器支持参数绑定);}}/*** 测试SimpleStatementHandler* 特点静态SQL直接执行*/private static void testSimpleStatementHandler(SqlSessionFactory factory) {System.out.println( 测试 SimpleStatementHandler );try (SqlSession session factory.openSession()) {// 使用StatementType.STATEMENT的映射System.out.println( 静态SQL查询);User user session.selectOne(com.example.UserMapper.findUserByStaticSql, 1L);System.out.println(查询结果: user);System.out.println(注意SimpleStatementHandler 用于静态SQL不支持参数绑定);}}/*** 测试CallableStatementHandler* 特点存储过程调用支持输入输出参数*/private static void testCallableStatementHandler(SqlSessionFactory factory) {System.out.println( 测试 CallableStatementHandler );try (SqlSession session factory.openSession()) {// 使用StatementType.CALLABLE的映射System.out.println( 存储过程调用);// 调用存储过程java.util.MapString, Object params new java.util.HashMap();params.put(userId, 1L);params.put(userName, null); // 输出参数session.selectOne(com.example.UserMapper.getUserByIdProc, params);System.out.println(存储过程执行结果: params);System.out.println(注意CallableStatementHandler 用于存储过程调用支持输出参数);}}}9. 源码调试指导9.1 关键断点位置RoutingStatementHandler断点RoutingStatementHandler.RoutingStatementHandler() - 路由选择逻辑RoutingStatementHandler.prepare() - 委托给具体处理器BaseStatementHandler断点BaseStatementHandler.parameterize() - 参数设置委托BaseStatementHandler.query() - 查询执行流程BaseStatementHandler.update() - 更新执行流程PreparedStatementHandler断点PreparedStatementHandler.instantiateStatement() - PreparedStatement创建PreparedStatementHandler.prepare() - Statement准备过程CallableStatementHandler断点CallableStatementHandler.registerOutputParameters() - 输出参数注册CallableStatementHandler.query() - 存储过程查询执行9.2 调试技巧观察Statement类型// 在StatementHandler创建时观察类型StatementHandler handler configuration.newStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);System.out.println(StatementHandler类型: handler.getClass().getSimpleName());观察SQL执行// 在prepare方法中观察SQLStatement stmt handler.prepare(connection, timeout);System.out.println(准备执行的SQL: boundSql.getSql());观察参数设置// 在parameterize方法中观察参数设置handler.parameterize(stmt);// 断点观察ParameterHandler.setParameters()方法10. 易错与排错清单10.1 常见问题问题 原因 解决方案SQL注入 使用SimpleStatementHandler处理用户输入 优先使用PreparedStatementHandler参数绑定失败 参数映射配置错误 检查ParameterMapping配置存储过程调用失败 输出参数未正确注册 确保正确配置OUT参数类型批量操作不生效 忘记调用batch()方法 确保在批量操作中调用batch()Statement泄漏 忘记关闭Statement 使用try-with-resources或确保关闭10.2 性能优化建议选择合适处理器根据SQL类型选择合适的StatementHandler参数化查询优先使用PreparedStatementHandler防止SQL注入批量操作优化大量操作使用批量模式连接池配置合理配置数据库连接池参数超时设置合理设置查询超时和事务超时11. 小结通过本文的学习我们深入了解了MyBatis StatementHandler语句处理器体系RoutingStatementHandler路由处理器根据StatementType选择具体的处理器实现BaseStatementHandler抽象基类提供通用的功能和组件管理PreparedStatementHandler预编译处理器支持参数绑定防止SQL注入CallableStatementHandler存储过程处理器支持输入输出参数