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 查询并处理ResultSet
StatementHandler
的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 执行需求.