mybatis四大神器之StatementHandler

Statementhandler是四大神器中最重要的一個(gè)對象,負(fù)責(zé)操作Statement與數(shù)據(jù)庫進(jìn)行交流.在工作時(shí)
還會(huì)使用ParameterHandler進(jìn)行參數(shù)配置,使用ResultHandler將查詢結(jié)果與實(shí)體類對象進(jìn)行綁定

我們使用原生jdbc的時(shí)候會(huì)有statement相關(guān)的操作

Statement stmt = conn.createStatement();

StatementHandler的構(gòu)成

源碼如下

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;

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

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

    BoundSql getBoundSql();

    ParameterHandler getParameterHandler();
}
  • prepare: 用于創(chuàng)建一個(gè)具體的 Statement 對象的實(shí)現(xiàn)類或者是 Statement 對象
  • parametersize: 用于初始化 Statement 對象以及對sql的占位符進(jìn)行賦值
  • update: 用于通知 Statement 對象將 insert、update、delete 操作推送到數(shù)據(jù)庫
  • query: 用于通知 Statement 對象將 select 操作推送數(shù)據(jù)庫并返回對應(yīng)的查詢結(jié)果

StatementHandler繼承結(jié)構(gòu)

image

可以看出StatementHandler的繼承體現(xiàn)和上一篇文章中的Executor的繼承體系很類似

StatementHandler是頂級(jí)的接口,下面有兩個(gè)直接實(shí)現(xiàn)類

  • RoutingStatementHandler:是一個(gè)具體實(shí)現(xiàn)類.在這個(gè)類中并沒有對Statement對象進(jìn)行具體使用.只是根據(jù)得到Executor類型,決定創(chuàng)建何種類型StatementHandler對象.在MyBatis工作時(shí),使用的StatementHandler接口對象實(shí)際上就是RoutingStatementHandler對象.我們可以簡單理解為

     StatementHandler statmentHandler = new RountingStatementHandler();
    
    public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    
      // 根據(jù) statementType 創(chuàng)建對應(yīng)的 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接口的另一個(gè)實(shí)現(xiàn)類.本身是一個(gè)抽象類.用于簡化StatementHandler接口實(shí)現(xiàn)的難度,屬于適配器設(shè)計(jì)模式體現(xiàn).它有三個(gè)實(shí)現(xiàn)類.SimpleStatementHandler,PreparedStatementHandler,CallableStatementHandler.
    在RountingStatementHandler創(chuàng)建時(shí),就跟根據(jù)接收的Executor類型來創(chuàng)建這個(gè)三個(gè)類型對象的.
    • SimpleStatementHandler:管理Statement對象向數(shù)據(jù)庫中推送不需要預(yù)編譯的SQL語句
    • PreparedStatementHandler:管理PreparedStatementHandler對象向數(shù)據(jù)庫推送預(yù)編譯的SQL語句
    • CallableStatementHandler:管理CallableStatement對象調(diào)用數(shù)據(jù)庫中構(gòu)造函數(shù)

StatementHandler對象創(chuàng)建

StatementHandler對象是在SqlSession對象接收到操作命令時(shí),由Configuraion中newStatementHandler方法負(fù)責(zé)調(diào)用的; Configuration 中的 newStatementHandler 是由執(zhí)行器中的查詢、更新方法來提供的,StatementHandler 其實(shí)就是由 Executor 負(fù)責(zé)管理和創(chuàng)建的

下面是SimpleExecutor中的update方法

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

        int var6;
        try {
            Configuration configuration = ms.getConfiguration();
            //創(chuàng)建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構(gòu)造方法,將會(huì)根據(jù)Executor的類型決定創(chuàng)建SimpleStatementHandler,PreparedStatementHandler,CallableStatementHandler實(shí)例對象

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被實(shí)現(xiàn).在其三個(gè)子類中沒有被重寫.用于三個(gè)子類調(diào)用獲得對應(yīng)的Statement接口對象.

prepare方法依靠instantiateStatement(connection)方法來返回具體Statement接口對象.
這個(gè)方法是BaseStatementHandler中定義的抽象方法,由三個(gè)子類來具體實(shí)現(xiàn).

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

在這兩個(gè)方法中,可以看到都是"ParameterHandler"對象進(jìn)行參數(shù)賦值的

query方法

輸送查詢查詢語句,并將查詢結(jié)果轉(zhuǎn)換對應(yīng)的實(shí)體類對象

SimpleStatementHandler 中的 query 方法

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

PreparedStatementHandler中的query方法

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

可以看到在得到查詢結(jié)果后,都是使用[ResultSetHandler]對結(jié)果進(jìn)行轉(zhuǎn)換

update

輸送insert,update,delete語句并返回處理數(shù)據(jù)行

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容