Mybatis—StatementHandler

  StatementHandler组件封装了对JDBC Statement的操作,其中包括设置Statement对象的fetchSize属性、设置查询超时时间、调用JDBC Statement与数据库交互。在Mybatis源代码中通常搭配Executor使用,如SimpleExecutor类的doQuery方法逻辑所示:

  1. 通过Configuration构造对应的StatementHandler;
  2. 通过调用StatementHandler的query方法来完成数据库操作。
@Override
public <E> List<E> doQuery(
    MappedStatement ms, Object parameter, 
    RowBounds rowBounds, ResultHandler resultHandler,
    BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
        Configuration configuration = ms.getConfiguration();
      	// 调用Configuration构造对应的StatementHandler
      	StatementHandler handler = configuration.newStatementHandler(
          	wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      	stmt = prepareStatement(handler, ms.getStatementLog());
      	// 通过调用StatementHandler query方法操作数据库  
      	return handler.query(stmt, resultHandler);
    } finally {
        closeStatement(stmt);
    }
}

  org.apache.ibatis.executor.SimpleExecutor#doQuery方法中利用Configuration#newStatementHandler方法来构造一个匹配的StatementHandler,其中newStatementHandler入参解释如下:

  1. Executor executor,SQL执行器
  2. MappedStatement mappedStatement,Mapper配置
  3. Object parameterObject,SQL参数用于构造ParameterHandler
  4. RowBounds rowBounds,分页
  5. ResultHandler resultHandler,SQL语句之后后的结构处理器
  6. BoundSql boundSql,SQL语句包装类
public StatementHandler newStatementHandler(
    Executor executor, MappedStatement mappedStatement,
    Object parameterObject, RowBounds rowBounds, 
    ResultHandler resultHandler, BoundSql boundSql) {

    // 通过RoutingStatementHandler构造函数构造StatementHandler
    StatementHandler statementHandler = new RoutingStatementHandler(
        executor, mappedStatement, parameterObject, 
        rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(
        statementHandler);
    return statementHandler;
}

  从源代码来看,Configuration#newStatementHandler方法利用RoutingStatementHandler类的构造方法来完成具体类型StatementHandler的构造,RoutingStatementHandler利用所传入的MappedStatement类型来构造对应类型的StatementHandler,具体的类型如org.apache.ibatis.mapping.StatementType枚举类中定义。

public RoutingStatementHandler(
    Executor executor, MappedStatement ms,
    Object parameter, RowBounds rowBounds, 
    ResultHandler resultHandler, BoundSql boundSql) {

    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(
            executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(
            executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(
            executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException(
            "Unknown statement type: " + ms.getStatementType());
    }

  }

结构

  StatementHandler采用了常用的装饰器和模板方法设计模式,如下图所示,StatementHandler接口下有BaseStatementHandler和RoutingStatementHandler两个实现类,其中BaseStatementHandler抽象类实现了一些基础的方法以供子类使用;RoutingStatementHandler类则通过构造方法来路由构造具体的StatementHandler类,以及通过获得的StatementHandler类来装饰实现StatementHandler接口方法。
  除了直接实现自StatementHandler接口的BaseStatementHandler和RoutingStatementHandler类以外,还有CallableStatementHandler、PreparedStatementHandler和SimpleStatementHandler三个继承自BaseStatementHandler抽象类的StatementHandler,这三个StatementHandler才是真正实现了对JDBC Statement操作的包装。
在这里插入图片描述

StatementHandler接口定义

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;

  <E> Cursor<E> queryCursor(Statement statement)
      throws SQLException;

  BoundSql getBoundSql();

  ParameterHandler getParameterHandler();
}

  从源代码来看StatementHandler接口定义了一些操作数据库的基本方法,

  • prepare,创建JDBC Statement对象,并完成Statement对象的属性设置。
  • parameterize,使用MyBatis中的ParameterHandler组件为PreparedStatement和CallableStatement参数占位符设置值。
  • batch,将SQL命令添加到批处量执行列表中。
  • update,调用Statement对象的execute()方法执行更新语句,例如UPDATE、INSERT、DELETE语句。
  • query,执行查询语句,并使用ResultSetHandler处理查询结果集。
  • queryCursor,带游标的查询返回Cursor对象。
  • getBoundSql,获取Mapper中配置的SQL信息,BoundSql封装了动态SQL解析后的SQL文本和参数映射信息。
  • getParameterHandler,获取ParameterHandler实例。

以小见大

  通过org.apache.ibatis.executor.statement.SimpleStatementHandler#query方法来简单窥探一下StatementHandler是如何完成对JDBC Statement的操作,要想完成一次对数据库的操作,需要拥有Statement、ResultHandler结果处理器和BoundSql SQL包装类三件工具,然后通过其相互配合完成一次对数据库的操作。

  1. 从BoundSql实体中获取对应的SQL语句;
  2. 将SQL语句传入Statement,然后执行SQL语句;
  3. 将SQL语句执行结果传入ResultHandler结果处理器,然后处理结果并返回其处理后的结果。
@Override
public <E> List<E> query(
    Statement statement, ResultHandler resultHandler) throws SQLException {
    
    String sql = boundSql.getSql();
    statement.execute(sql);
    return resultSetHandler.handleResultSets(statement);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乐只乐之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值