Mybatis3源码分析(14)-Sql解析执行-StatementHandler

撸了今年阿里、腾讯和美团的面试,我有一个重要发现…….

作者:ashan_li

出处:https://blog.csdn.net/ashan_li/article/category/6047775/1?


SimpleExecutor执行sql过程

BoundSql加载完成之后,下一步就可以执行select/update/insert/delete语句了。在SimpleExecutor中执行语句最终会由doQuery和doUpdate方法完成。

     public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Statement stmt = null;
        try {
          Configuration configuration = ms.getConfiguration();
          //生成一个StatementHandler
          StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
          //执行之前的准备
          stmt = prepareStatement(handler, ms.getStatementLog());
          //执行sql
          return handler.update(stmt);
        } finally {
          closeStatement(stmt);
        }
      }

      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();
          //生成一个StatementHandler
          StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
          //执行之前的准备
          stmt = prepareStatement(handler, ms.getStatementLog());
          //执行sql
          return handler.<E>query(stmt, resultHandler);
        } finally {
          closeStatement(stmt);
        }
      }
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Statement stmt;
        //获取一个连接
        Connection connection = getConnection(statementLog);
        //由StatementHandler从connection获取一个StatementHandler
        stmt = handler.prepare(connection);
        //设置执行参数
        handler.parameterize(stmt);
        return stmt;
      }

从以上代码中可以到出Executor是怎么利用StatementHandler执行SQL的

  1. 获取一个数据库连接
  2. 调用StatementHandler.prepare()方法获取一个statement
  3. 调用StatementHandler.parameterize()方法设置sql执行时所需要的参数
  4. 调用StatementHandler.update或query方法执行sql

StatementHandler

这个接口定义了执行sql的基本操作

    public interface StatementHandler {
      //从连接中获取一个Statement
      Statement prepare(Connection connection)
          throws SQLException;


      //设置statement执行里所需的参数
      void parameterize(Statement statement)
          throws SQLException;

      //批量
      void batch(Statement statement)
          throws SQLException;

      //更新:update/insert/delete语句
      int update(Statement statement)
          throws SQLException;

      //执行查询
      <E> List<E> query(Statement statement, ResultHandler resultHandler)
          throws SQLException;

      BoundSql getBoundSql();

      ParameterHandler getParameterHandler();

    }

再来看他的类关系图

2019080910014_1.png

跟Executor的实现非常相似。

2019080910014_2.png

RoutingStatementHandler

这个类只是根据MappedStatement的配置,生成一个对应的StatementHandler(delegate),然后所有的实现都由delegate完成。

    private final StatementHandler delegate;

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

      }

BaseStatementHandler

这个类是一个模板类。其中有两个主要的属性和一个主要的方法。先来看两个属性。

      //处理结果的Handler
      protected final ResultSetHandler resultSetHandler;
      //设置参数的Handler
      protected final ParameterHandler parameterHandler;
    public interface ResultSetHandler {
      //转换结果集
      <E> List<E> handleResultSets(Statement stmt) throws SQLException;

      void handleOutputParameters(CallableStatement cs) throws SQLException;

    }
    public interface ParameterHandler {

      Object getParameterObject();
      //设置SQL执行的参数
      void setParameters(PreparedStatement ps)
          throws SQLException;

    }

这ParameterHandler和ResultSetHandler在Mybatis中都只有一个实现:DefaultParameterHandler和DefaultResultSetHandler。之后会有详细有分析。

Prepare方法

    public Statement prepare(Connection connection) throws SQLException {
        ErrorContext.instance().sql(boundSql.getSql());
        Statement statement = null;
        try {
          //这个方法是抽象的,由子类实现
          statement = instantiateStatement(connection);
          //设置执行的超时时间
          setStatementTimeout(statement);
          //fetchSize,对大的结果集才有明显的效果
          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);
        }
      }

BaseStatementHandler子类

  1. PreparedStatementHandler,处理PreparedStatement对象,即带参数运行的SQL,这个类以后详细分析。
  2. CallableStatementHandler,处理CallableStatement对象,即执行过程的SQL,不做讨论。
  3. SimpleStatementHandler,处理Statement对象,即不带参数运行的SQL,不做讨论。
赞(0) 打赏

如未加特殊说明,此网站文章均为原创,转载必须注明出处。Java 技术驿站 » Mybatis3源码分析(14)-Sql解析执行-StatementHandler
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

关注【Java 技术驿站】公众号,每天早上 8:10 为你推送一篇技术文章

扫描二维码关注我!


关注【Java 技术驿站】公众号 回复 “VIP”,获取 VIP 地址永久关闭弹出窗口

免费获取资源

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏