StatementHandler 在 MyBatis 中扮演着 连接 MyBatis 框架和 JDBC API 的桥梁 的角色。 它的核心作用是 处理 JDBC Statement 对象,并负责 MyBatis 与数据库的实际交互。 StatementHandler 封装了所有与 JDBC Statement 对象相关的操作,使得 MyBatis 的其他组件 (例如 Executor) 无需直接操作 JDBC API,而是通过 StatementHandler 提供的接口与数据库进行交互。
StatementHandler 与数据库交互的核心步骤和机制:
-
StatementHandler的创建:StatementHandler实例由Executor创建。Executor会根据MappedStatement对象中定义的statementType属性 (例如STATEMENT,PREPARED,CALLABLE),创建不同类型的StatementHandler实现类实例 (例如SimpleStatementHandler,PreparedStatementHandler,CallableStatementHandler)。StatementHandler的创建通常发生在Executor.query()或Executor.update()等 SQL 执行方法内部,在真正执行 SQL 语句之前。
-
StatementHandler.prepare()方法:准备 JDBCStatement对象StatementHandler的prepare(Connection connection, Integer transactionTimeout)方法负责 创建 JDBCStatement对象。- 根据
MappedStatement的statementType属性,创建不同类型的Statement对象:statementType="STATEMENT": 创建java.sql.Statement对象 (普通 Statement)。 适用于不需要预编译 SQL 或参数绑定的简单 SQL 语句。statementType="PREPARED"(默认): 创建java.sql.PreparedStatement对象 (预编译 Statement)。 适用于大多数场景,可以提高性能和安全性,支持参数绑定。statementType="CALLABLE": 创建java.sql.CallableStatement对象 (可调用 Statement)。 适用于调用数据库存储过程或函数。
- 使用传入的
Connection对象创建Statement。Connection对象通常由Transaction对象提供,代表当前事务的数据库连接。 - 设置
Statement的超时时间 (transactionTimeout)。 如果transactionTimeout不为null,会调用statement.setQueryTimeout(transactionTimeout)设置 Statement 的超时时间,防止 SQL 执行时间过长。 - 返回创建好的 JDBC
Statement对象。
-
StatementHandler.parameterize()方法:设置 SQL 参数StatementHandler的parameterize(Statement statement)方法负责 为 JDBCStatement对象设置 SQL 参数。- 根据
MappedStatement中定义的参数映射 (ParameterMapping),从传入的参数对象 (parameterObject) 中获取参数值。 参数映射信息包括参数的属性名、jdbcType、typeHandler 等。 - 使用
TypeHandler将 Java 参数值转换为 JDBC 类型的值,并通过 JDBCStatement的setXXX()方法 (例如PreparedStatement.setString(),PreparedStatement.setInt(),CallableStatement.registerOutParameter()等) 将参数值设置到Statement对象中。 - 不同类型的
StatementHandler实现类,会采用不同的参数设置方式:PreparedStatementHandler: 使用PreparedStatement.setXXX()方法设置参数 (最常用)。CallableStatementHandler: 使用CallableStatement.setXXX()设置输入参数,使用CallableStatement.registerOutParameter()注册输出参数。SimpleStatementHandler: 对于Statement对象,参数通常直接拼接在 SQL 语句中 (不安全,不推荐)。 在 MyBatis 中,SimpleStatementHandler实际上并不直接处理参数设置 (参数设置通常交给ParameterHandler完成,ParameterHandler再委托给TypeHandler进行类型转换和参数设置)。
-
StatementHandler.query()方法:执行 SQL 查询并处理ResultSetStatementHandler的query(Statement statement, ResultHandler resultHandler)方法负责 执行 SQL 查询语句,并处理查询结果集 (ResultSet)。- 调用 JDBC
Statement.execute()或Statement.executeQuery()方法执行 SQL 查询语句,获取ResultSet对象。 具体调用哪个方法取决于MappedStatement的 SQL 类型 (SELECT 调用executeQuery(), 其他调用execute())。 - 使用
ResultHandler对象逐行处理ResultSet。ResultHandler负责遍历ResultSet,并根据ResultMap或resultType定义的映射规则,将每一行数据映射到 Java 对象。 - 返回查询结果列表 (List)。
ResultHandler会将映射后的 Java 对象添加到结果列表中,query()方法最终返回这个结果列表。 - 在处理
ResultSet过程中,StatementHandler会委托给ResultSetHandler组件进行更具体的结果集处理和映射操作。
-
StatementHandler.update()方法:执行 SQL 更新语句StatementHandler的update(Statement statement)方法负责 执行 SQL 更新语句 (INSERT, UPDATE, DELETE)。- 调用 JDBC
Statement.execute()或Statement.executeUpdate()方法执行 SQL 更新语句。 具体调用哪个方法取决于MappedStatement的 SQL 类型 (INSERT, UPDATE, DELETE 通常调用executeUpdate(), 某些特殊情况可能调用execute()). - 返回受影响的行数 (int)。
update()方法返回执行 SQL 更新语句后,数据库受影响的行数。
-
StatementHandler.batch()方法:执行批量 SQL 语句 (BatchExecutor 使用)StatementHandler的batch(Statement statement)方法负责 执行批量 SQL 语句 (BatchExecutor 使用)。- 将多条 SQL 语句添加到 JDBC
Statement对象的批处理队列中 (例如PreparedStatement.addBatch()). - 在所有 SQL 语句添加到批处理队列后,调用
Statement.executeBatch()方法一次性执行批处理队列中的所有 SQL 语句。 - 返回一个
List<BatchResult>, 包含了每条 SQL 语句的执行结果 (受影响的行数或异常信息)。
StatementHandler 接口的主要方法:
StatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)(构造器): 创建StatementHandler实例。Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;: 准备 JDBCStatement对象。void parameterize(Statement statement) throws SQLException;: 为 JDBCStatement对象设置 SQL 参数。<E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;: 执行 SQL 查询语句,并处理结果集。int update(Statement statement) throws SQLException;: 执行 SQL 更新语句 (INSERT, UPDATE, DELETE)。void batch(Statement statement) throws SQLException;: 执行批量 SQL 语句 (BatchExecutor 使用)。
StatementHandler 的实现类:
MyBatis 提供了以下几种 StatementHandler 接口的实现类,对应不同的 JDBC Statement 类型:
SimpleStatementHandler: 处理java.sql.Statement对象 (普通 Statement)。 最简单的StatementHandler实现。PreparedStatementHandler: 处理java.sql.PreparedStatement对象 (预编译 Statement)。 最常用的StatementHandler实现。CallableStatementHandler: 处理java.sql.CallableStatement对象 (可调用 Statement)。 用于调用数据库存储过程或函数。RoutingStatementHandler: 路由StatementHandler。 根据MappedStatement的statementType属性,动态地选择使用SimpleStatementHandler,PreparedStatementHandler, 或CallableStatementHandler中的一个。RoutingStatementHandler本身不直接处理Statement,而是作为其他StatementHandler的路由和委托。
总结 StatementHandler 与数据库的交互:
StatementHandler是 MyBatis 与数据库交互的桥梁,负责处理 JDBCStatement对象。StatementHandler通过prepare(),parameterize(),query(),update(),batch()等方法,完成 JDBCStatement对象的创建、参数设置、SQL 执行和结果处理等操作。StatementHandler内部使用 JDBC API (例如Connection,Statement,ResultSet) 与数据库进行交互。StatementHandler抽象了底层的 JDBC 操作细节,为 MyBatis 的其他组件提供了更高层次的、更易于使用的 SQL 执行接口。- MyBatis 提供了多种
StatementHandler实现类,对应不同的 JDBCStatement类型,满足不同的 SQL 执行需求.
