当前位置: 首页 > news >正文

块状数组超级兵器:区间动态排名问题

玫瞬谑哦1. 学习目标确认

1.0 第5篇思考题解答

在深入学习StatementHandler语句处理器之前,让我们先回顾并解答第5篇中提出的思考题,这将帮助我们更好地理解StatementHandler在整个架构中的作用。

思考题1:为什么MyBatis要设计多种Executor类型?它们各自的优势是什么?

答案要点:

SimpleExecutor:简单可靠,每次创建新Statement,适合大多数场景,资源管理清晰

ReuseExecutor:重用Statement对象,减少创建开销,适合重复执行相同SQL的场景

BatchExecutor:批量执行多个SQL,大幅减少数据库交互次数,适合批量数据操作

CachingExecutor:装饰器模式实现二级缓存,提升查询性能,适合读多写少的场景

设计理念:不同场景有不同需求,通过多种执行器满足不同性能要求

StatementHandler的作用:StatementHandler是Executor的核心组件,负责具体的SQL语句预处理、参数设置和结果处理。

思考题2:BaseExecutor的模板方法模式是如何实现的?这种设计有什么优势?

答案要点:

模板方法定义:BaseExecutor定义了query()和update()的标准流程,包含缓存检查、错误处理、延迟加载等通用逻辑

抽象方法实现:子类只需实现doQuery()和doUpdate()等具体方法,专注于自己的核心逻辑

优势体现:代码复用、逻辑统一、扩展性强、维护性好

一级缓存管理:BaseExecutor统一管理一级缓存的生命周期和策略

与StatementHandler的协作:BaseExecutor通过StatementHandler执行具体的SQL操作,StatementHandler是模板方法中具体实现的关键组件。

思考题3:CachingExecutor的装饰器模式是如何工作的?与一级缓存有什么区别?

答案要点:

装饰器模式: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?

StatementHandler

+prepare(Connection, Integer) : Statement

+parameterize(Statement) : void

+batch(Statement) : void

+update(Statement) : int

+query(Statement, ResultHandler) : List

+queryCursor(Statement) : Cursor

+getBoundSql() : BoundSql

+getParameterHandler() : ParameterHandler

+getResultSetHandler() : 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) : Statement

RoutingStatementHandler

-delegate StatementHandler

+RoutingStatementHandler(Executor, MappedStatement, Object, RowBounds, ResultHandler, BoundSql)

+prepare(Connection, Integer) : Statement

+parameterize(Statement) : void

+batch(Statement) : void

+update(Statement) : int

+query(Statement, ResultHandler) : List

+queryCursor(Statement) : Cursor

+getBoundSql() : BoundSql

+getParameterHandler() : ParameterHandler

+getResultSetHandler() : ResultSetHandler

PreparedStatementHandler

-preparedStatement PreparedStatement

+prepare(Connection, Integer) : PreparedStatement

+parameterize(PreparedStatement) : void

+batch(PreparedStatement) : void

+update(PreparedStatement) : int

+query(PreparedStatement, ResultHandler) : List

+queryCursor(PreparedStatement) : Cursor

CallableStatementHandler

-callableStatement CallableStatement

+prepare(Connection, Integer) : CallableStatement

+parameterize(CallableStatement) : void

+batch(CallableStatement) : void

+update(CallableStatement) : int

+query(CallableStatement, ResultHandler) : List

+queryCursor(CallableStatement) : Cursor

SimpleStatementHandler

-statement Statement

+prepare(Connection, Integer) : Statement

+parameterize(Statement) : void

+batch(Statement) : void

+update(Statement) : int

+query(Statement, ResultHandler) : List

+queryCursor(Statement) : Cursor

2.2 语句处理器职责分工

处理器类型 核心职责 适用场景 特点

RoutingStatementHandler 路由选择具体的StatementHandler 所有场景的入口 根据StatementType路由到具体实现

PreparedStatementHandler 处理PreparedStatement 参数化查询 支持参数绑定,防止SQL注入

CallableStatementHandler 处理CallableStatement 存储过程调用 支持输入输出参数

SimpleStatementHandler 处理Statement 静态SQL 简单直接,无参数绑定

2.3 语句处理器协作关系

Database

ResultSetHandler

ParameterHandler

StatementHandler

Executor

Database

ResultSetHandler

ParameterHandler

StatementHandler

Executor

newStatementHandler(ms, param, rowBounds, handler, boundSql)

prepare(connection, timeout)

create Statement

Statement

parameterize(statement)

set parameters

parameters set

execute query/update

ResultSet/UpdateCount

handleResultSets(statement)

List

results

3. 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());

}

}

@Override

public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {

return delegate.prepare(connection, transactionTimeout);

}

@Override

public void parameterize(Statement statement) throws SQLException {

delegate.parameterize(statement);

}

@Override

public void batch(Statement statement) throws SQLException {

delegate.batch(statement);

}

@Override

public int update(Statement statement) throws SQLException {

return delegate.update(statement);

}

@Override

public List query(Statement statement, ResultHandler resultHandler) throws SQLException {

return delegate.query(statement, resultHandler);

}

@Override

public Cursor queryCursor(Statement statement) throws SQLException {

return delegate.queryCursor(statement);

}

@Override

public BoundSql getBoundSql() {

return delegate.getBoundSql();

}

@Override

public ParameterHandler getParameterHandler() {

return delegate.getParameterHandler();

}

@Override

public ResultSetHandler getResultSetHandler() {

return delegate.getResultSetHandler();

}

@Override

public Object plugin(Object target) {

return Plugin.wrap(target, this);

}

}

3.2 路由策略

RoutingStatementHandler根据MappedStatement中的StatementType进行路由:

// StatementType枚举定义

public enum StatementType {

STATEMENT, // 对应Statement(静态SQL)

PREPARED, // 对应PreparedStatement(参数化SQL)

CALLABLE // 对应CallableStatement(存储过程)

}

// 路由逻辑

switch (ms.getStatementType()) {

case STATEMENT:

// 使用SimpleStatementHandler处理静态SQL

delegate = 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创建逻辑

*/

@Override

public abstract Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;

/**

* 设置参数

* 委托给ParameterHandler处理

*/

@Override

public void parameterize(Statement statement) throws SQLException {

parameterHandler.setParameters(statement);

}

/**

* 批量操作

* 委托给ParameterHandler处理

*/

@Override

public void batch(Statement statement) throws SQLException {

parameterHandler.batch(statement);

}

/**

* 执行更新操作

* 委托给具体的Statement执行

*/

@Override

public 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处理结果集

*/

@Override

public List query(Statement statement, ResultHandler resultHandler) throws SQLException {

PreparedStatement ps = (PreparedStatement) statement;

ps.execute();

return resultSetHandler.handleResultSets(ps);

}

/**

* 执行游标查询

* 委托给ResultSetHandler处理

*/

@Override

public Cursor queryCursor(Statement statement) throws SQLException {

PreparedStatement ps = (PreparedStatement) statement;

ps.execute();

return resultSetHandler.handleCursorResultSets(ps);

}

@Override

public BoundSql getBoundSql() {

return boundSql;

}

@Override

public ParameterHandler getParameterHandler() {

return parameterHandler;

}

@Override

public 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);

// 委托执行

@Override

public void parameterize(Statement statement) throws SQLException {

parameterHandler.setParameters(statement); // 委托给ParameterHandler

}

@Override

public List 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对象

*/

@Override

public 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对象

*/

@Override

protected Statement instantiateStatement(Connection connection) throws SQLException {

String sql = boundSql.getSql();

// 根据KeyGenerator类型创建不同的PreparedStatement

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 {

// 普通PreparedStatement

return connection.prepareStatement(sql);

}

}

/**

* 设置参数

* 委托给ParameterHandler处理

*/

@Override

public void parameterize(Statement statement) throws SQLException {

parameterHandler.setParameters((PreparedStatement) statement);

}

/**

* 批量操作

*/

@Override

public void batch(Statement statement) throws SQLException {

PreparedStatement ps = (PreparedStatement) statement;

ps.addBatch();

}

/**

* 执行更新操作

*/

@Override

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

}

/**

* 执行查询操作

*/

@Override

public List query(Statement statement, ResultHandler resultHandler) throws SQLException {

PreparedStatement ps = (PreparedStatement) statement;

ps.execute();

return resultSetHandler.handleResultSets(ps);

}

/**

* 执行游标查询

*/

@Override

public Cursor 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对象

*/

@Override

public 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对象

*/

@Override

protected Statement instantiateStatement(Connection connection) throws SQLException {

String sql = boundSql.getSql();

// 创建CallableStatement

if (mappedStatement.getResultSetType() != null) {

return connection.prepareCall(sql,

mappedStatement.getResultSetType().getValue(),

ResultSet.CONCUR_READ_ONLY);

} else {

return connection.prepareCall(sql);

}

}

/**

* 设置参数

* 存储过程支持输入、输出和输入输出参数

*/

@Override

public void parameterize(Statement statement) throws SQLException {

// 注册输出参数

registerOutputParameters((CallableStatement) statement);

// 设置输入参数

parameterHandler.setParameters((CallableStatement) statement);

}

/**

* 批量操作

* 存储过程通常不支持批量操作

*/

@Override

public void batch(Statement statement) throws SQLException {

CallableStatement cs = (CallableStatement) statement;

cs.addBatch();

}

/**

* 执行更新操作

*/

@Override

public int update(Statement statement) throws SQLException {

CallableStatement cs = (CallableStatement) statement;

cs.execute();

int rows = cs.getUpdateCount();

// 处理输出参数

resultSetHandler.handleOutputParameters(cs);

return rows;

}

/**

* 执行查询操作

*/

@Override

public List query(Statement statement, ResultHandler resultHandler) throws SQLException {

CallableStatement cs = (CallableStatement) statement;

cs.execute();

List resultList = resultSetHandler.handleResultSets(cs);

// 处理输出参数

resultSetHandler.handleOutputParameters(cs);

return resultList;

}

/**

* 执行游标查询

*/

@Override

public Cursor queryCursor(Statement statement) throws SQLException {

CallableStatement cs = (CallableStatement) statement;

cs.execute();

Cursor cursor = resultSetHandler.handleCursorResultSets(cs);

// 处理输出参数

resultSetHandler.handleOutputParameters(cs);

return cursor;

}

/**

* 注册输出参数

* 根据参数映射配置注册输出参数的类型

*/

private void registerOutputParameters(CallableStatement cs) throws SQLException {

List 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对象

*/

@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);

// 设置获取大小

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对象

*/

@Override

protected Statement instantiateStatement(Connection connection) throws SQLException {

// 创建普通Statement

if (mappedStatement.getResultSetType() != null) {

return connection.createStatement(

mappedStatement.getResultSetType().getValue(),

ResultSet.CONCUR_READ_ONLY);

} else {

return connection.createStatement();

}

}

/**

* 设置参数

* Statement不支持参数绑定,直接执行SQL

*/

@Override

public void parameterize(Statement statement) throws SQLException {

// Statement不支持参数化,无需设置参数

// 参数已经直接拼接到SQL中

}

/**

* 批量操作

*/

@Override

public void batch(Statement statement) throws SQLException {

Statement stmt = (Statement) statement;

stmt.addBatch(boundSql.getSql());

}

/**

* 执行更新操作

*/

@Override

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

}

/**

* 执行查询操作

*/

@Override

public List query(Statement statement, ResultHandler resultHandler) throws SQLException {

Statement stmt = (Statement) statement;

stmt.execute(boundSql.getSql());

return resultSetHandler.handleResultSets(stmt);

}

/**

* 执行游标查询

*/

@Override

public Cursor 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. 实践案例:自定义StatementHandler

8.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; // 是否启用统计

@Override

public 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());

}

@Override

public Object plugin(Object target) {

return Plugin.wrap(target, this);

}

@Override

public 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中配置插件:

8.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);

// 测试不同类型的StatementHandler

testPreparedStatementHandler(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("newemail@example.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.Map 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方法中观察SQL

Statement stmt = handler.prepare(connection, timeout);

System.out.println("准备执行的SQL: " + boundSql.getSql());

观察参数设置:

// 在parameterize方法中观察参数设置

handler.parameterize(stmt);

// 断点观察ParameterHandler.setParameters()方法

10. 易错与排错清单

http://www.dtcms.com/a/593380.html

相关文章:

  • 在网站开发中如何设置用户登录网站查看
  • SAP FICO资产主数据创建接口
  • 『 QT 』显示类控件 (一)
  • 网站建设彳金手指排名wordpress电子书插件
  • 石狮网站建设科技vmware做网站步骤
  • 全国网站建设公司排名泰安市人才交流服务中心
  • C++双向链表删除操作:由浅入深完全指南
  • 云手机轻松玩转网络手游
  • 手机拍照明晰度评估:传感器尺寸像素数量与处理器算法解析
  • Web VIVO手机商城网站项目4页面
  • 【杂谈】-人工智能时代的基础设施变革:引领未来十年科技发展的关键
  • 有关网络技术的网站iis7 建立网站
  • vue提交代码报错---eslint检查
  • 天津外贸公司网站制作wordpress中国区官方论坛
  • 成都企业网站商城定制网络推广方案包括哪些内容
  • 商城网站建设机构怎样做展示型网站
  • Rust类型系统奇技淫巧:幽灵类型(PhantomData)——理解编译器与类型安全
  • Visual Studio Code 之C/C++开发编译环境搭建
  • 长沙网站制造太原网站建设注意
  • PortSwigger靶场之SSRF with whitelist-based input filter通关秘籍
  • 太原网站快速排名提升手机商城网站制作公司
  • Redis 核心命令速查表
  • 中药饮片批发市场如何提升产品质量以迎合客户需求?
  • k8s中应用容器随redis集群自动重启
  • C语言结构体入门与实践:打造你的“数据百宝箱”
  • Docker核心概念与实战指南
  • 视频网站开发问题整人网站建设
  • 【Java】面向对象编程
  • 作业11.9
  • 西安网站开发公司网站服务器租用价格