模板方法模式的应用之 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 对象)的细节交给子类实现。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构