模板方法模式的应用之 MyBatis BaseStatementHandler

MyBatis StatementHandler 接口主要负责 SQL 语句的执行和参数的设置:

public interface StatementHandler {
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;
void parameterize(Statement statement)
throws SQLException;
void batch(Statement statement)
throws SQLException;
int update(Statement statement)
throws SQLException;
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;
// ...
}

BaseStatementHandler 类是 StatementHandler 接口的抽象实现类,它定义了 StatementHandler 接口需要实现的大部分方法,包括对参数的设置、SQL 语句的执行等,并提供了一个抽象方法 instantiateStatement(Connection connection),供子类实例化 Statement 对象:

public abstract class BaseStatementHandler implements StatementHandler {
// ...
@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 对象(子类实现)
*/
protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
// ...
}

StatementHandler 的实现类 SimpleStatementHandler、PreparedStatementHandler 和 CallableStatementHandler 分别对应不同的 Statement 对象,比如 SimpleStatementHandler 使用 Statement 对象执行 SQL 语句,PreparedStatementHandler 使用 PreparedStatement 对象执行 SQL 语句,CallableStatementHandler 使用 CallableStatement 对象执行 SQL 语句,它们都继承自 BaseStatementHandler 类,并实现了不同的 instantiateStatement() 方法,以 PreparedStatement 为例:

public class PreparedStatementHandler extends BaseStatementHandler {
// ...
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
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);
}
}
// ...
}

可以看到,PreparedStatementHandler 通过调用 connection.prepareStatement() 方法实例化了一个 PreparedStatement 对象,并返回了该对象。

在这里,BaseStatementHandler 中的 prepare() 方法就是模板方法,其中定义了 prepare(准备)的通用步骤,instantiateStatement(实例化 Statement 对象)的细节交给子类实现。

posted @   Higurashi-kagome  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示