mybatis四大神器之StatementHandler

Statementhandler是四大神器中最重要的一个对象,负责操作Statement与数据库进行交流.在工作时
还会使用ParameterHandler进行参数配置,使用ResultHandler将查询结果与实体类对象进行绑定

我们使用原生jdbc的时候会有statement相关的操作

Statement stmt = conn.createStatement();

StatementHandler的构成

源码如下

public interface StatementHandler {
    Statement prepare(Connection var1, Integer var2) throws SQLException;

    void parameterize(Statement var1) throws SQLException;

    void batch(Statement var1) throws SQLException;

    int update(Statement var1) throws SQLException;

     List query(Statement var1, ResultHandler var2) throws SQLException;

     Cursor queryCursor(Statement var1) throws SQLException;

    BoundSql getBoundSql();

    ParameterHandler getParameterHandler();
}
  • prepare: 用于创建一个具体的 Statement 对象的实现类或者是 Statement 对象
  • parametersize: 用于初始化 Statement 对象以及对sql的占位符进行赋值
  • update: 用于通知 Statement 对象将 insert、update、delete 操作推送到数据库
  • query: 用于通知 Statement 对象将 select 操作推送数据库并返回对应的查询结果

StatementHandler继承结构

image

可以看出StatementHandler的继承体现和上一篇文章中的Executor的继承体系很类似

StatementHandler是顶级的接口,下面有两个直接实现类

  • RoutingStatementHandler:是一个具体实现类.在这个类中并没有对Statement对象进行具体使用.只是根据得到Executor类型,决定创建何种类型StatementHandler对象.在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象.我们可以简单理解为

     StatementHandler statmentHandler = new RountingStatementHandler();
    
    public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    
      // 根据 statementType 创建对应的 Statement 对象
      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:是StatementHandler接口的另一个实现类.本身是一个抽象类.用于简化StatementHandler接口实现的难度,属于适配器设计模式体现.它有三个实现类.SimpleStatementHandler,PreparedStatementHandler,CallableStatementHandler.
    在RountingStatementHandler创建时,就跟根据接收的Executor类型来创建这个三个类型对象的.
    • SimpleStatementHandler:管理Statement对象向数据库中推送不需要预编译的SQL语句
    • PreparedStatementHandler:管理PreparedStatementHandler对象向数据库推送预编译的SQL语句
    • CallableStatementHandler:管理CallableStatement对象调用数据库中构造函数

StatementHandler对象创建

StatementHandler对象是在SqlSession对象接收到操作命令时,由Configuraion中newStatementHandler方法负责调用的; Configuration 中的 newStatementHandler 是由执行器中的查询、更新方法来提供的,StatementHandler 其实就是由 Executor 负责管理和创建的

下面是SimpleExecutor中的update方法

public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Statement stmt = null;

        int var6;
        try {
            Configuration configuration = ms.getConfiguration();
            //创建StatementHandler,解析sql
            StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
            stmt = this.prepareStatement(handler, ms.getStatementLog());
           //handler解析sql
            var6 = handler.update(stmt);
        } finally {
            this.closeStatement(stmt);
        }

        return var6;
    }
image

由上图可以看出RoutingStatementHandler构造方法,将会根据Executor的类型决定创建SimpleStatementHandler,PreparedStatementHandler,CallableStatementHandler实例对象

StatementHandler接口方法

prepare

public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
        ErrorContext.instance().sql(this.boundSql.getSql());
        Statement statement = null;

        try {
            statement = this.instantiateStatement(connection);
            this.setStatementTimeout(statement, transactionTimeout);
            this.setFetchSize(statement);
            return statement;
        } catch (SQLException var5) {
            this.closeStatement(statement);
            throw var5;
        } catch (Exception var6) {
            this.closeStatement(statement);
            throw new ExecutorException("Error preparing statement.  Cause: " + var6, var6);
        }
    }

prepare方法只在BaseStatementHandler被实现.在其三个子类中没有被重写.用于三个子类调用获得对应的Statement接口对象.

prepare方法依靠instantiateStatement(connection)方法来返回具体Statement接口对象.
这个方法是BaseStatementHandler中定义的抽象方法,由三个子类来具体实现.

 protected abstract Statement instantiateStatement(Connection var1) throws SQLException;

SimpleStatementHandler中的instantiateStatement 方法

  protected Statement instantiateStatement(Connection connection) throws SQLException {
        return this.mappedStatement.getResultSetType() != null ? connection.createStatement(this.mappedStatement.getResultSetType().getValue(), 1007) : connection.createStatement();
    }

PreparedStatementHandler中的instantiateStatement方法

protected Statement instantiateStatement(Connection connection) throws SQLException {
        String sql = this.boundSql.getSql();
        if (this.mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
            String[] keyColumnNames = this.mappedStatement.getKeyColumns();
            return keyColumnNames == null ? connection.prepareStatement(sql, 1) : connection.prepareStatement(sql, keyColumnNames);
        } else {
            return this.mappedStatement.getResultSetType() != null ? connection.prepareStatement(sql, this.mappedStatement.getResultSetType().getValue(), 1007) : connection.prepareStatement(sql);
        }
    }

CallableStatementHandler中的instantiateStatement方法

  protected Statement instantiateStatement(Connection connection) throws SQLException {
        String sql = this.boundSql.getSql();
        return this.mappedStatement.getResultSetType() != null ? connection.prepareCall(sql, this.mappedStatement.getResultSetType().getValue(), 1007) : connection.prepareCall(sql);
    }

parameterize方法

主要为PreparedStatement和CallableStatement传参.因此只在PreparedStatementHandler和CallableStatementHandler中被重写PreparedStatementHandler中的parameterize

PreparedStatementHandler中的parameterize

 public void parameterize(Statement statement) throws SQLException {
        this.parameterHandler.setParameters((PreparedStatement)statement);
    }

CallableStatementHandler中的parameterize

public void parameterize(Statement statement) throws SQLException {
        this.registerOutputParameters((CallableStatement)statement);
        this.parameterHandler.setParameters((CallableStatement)statement);
    }

在这两个方法中,可以看到都是"ParameterHandler"对象进行参数赋值的

query方法

输送查询查询语句,并将查询结果转换对应的实体类对象

SimpleStatementHandler 中的 query 方法

 public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
        String sql = this.boundSql.getSql();
        statement.execute(sql);
        return this.resultSetHandler.handleResultSets(statement);
    }

PreparedStatementHandler中的query方法

   public  List query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement)statement;
        ps.execute();
        return this.resultSetHandler.handleResultSets(ps);
    }

可以看到在得到查询结果后,都是使用[ResultSetHandler]对结果进行转换

update

输送insert,update,delete语句并返回处理数据行

SimpleStatementHandler中的update方法

  public int update(Statement statement) throws SQLException {
        String sql = this.boundSql.getSql();
        Object parameterObject = this.boundSql.getParameterObject();
        KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator();
        int rows;
        if (keyGenerator instanceof Jdbc3KeyGenerator) {
            statement.execute(sql, 1);
            rows = statement.getUpdateCount();
            keyGenerator.processAfter(this.executor, this.mappedStatement, statement, parameterObject);
        } else if (keyGenerator instanceof SelectKeyGenerator) {
            statement.execute(sql);
            rows = statement.getUpdateCount();
            keyGenerator.processAfter(this.executor, this.mappedStatement, statement, parameterObject);
        } else {
            statement.execute(sql);
            rows = statement.getUpdateCount();
        }

        return rows;
    }

PreparedStatementHandler中update方法

 public int update(Statement statement) throws SQLException {
        PreparedStatement ps = (PreparedStatement)statement;
        ps.execute();
        int rows = ps.getUpdateCount();
        Object parameterObject = this.boundSql.getParameterObject();
        KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator();
        keyGenerator.processAfter(this.executor, this.mappedStatement, ps, parameterObject);
        return rows;
    }

CallableStatementHandler中update方法

 public int update(Statement statement) throws SQLException {
        CallableStatement cs = (CallableStatement)statement;
        cs.execute();
        int rows = cs.getUpdateCount();
        Object parameterObject = this.boundSql.getParameterObject();
        KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator();
        keyGenerator.processAfter(this.executor, this.mappedStatement, cs, parameterObject);
        this.resultSetHandler.handleOutputParameters(cs);
        return rows;
    }

原文地址

http://cbaj.gitee.io/blog/2020/07/25/mybatis%E5%9B%9B%E5%A4%A7%E7%A5%9E%E5%99%A8%E4%B9%8BStatementHandler/#more

你可能感兴趣的:(mybatis四大神器之StatementHandler)