天天看點

MyBatis源碼-解讀Executor的三個實作類之SimpleExecutor(簡單執行器)

文章目錄

  • ​​Pre​​
  • ​​Executor 執行器​​
  • ​​接口繼承關系​​
  • ​​SimpleExecutor(簡單執行器)​​
  • ​​入門小demo​​
  • ​​執行個體化SimpleExecutor​​
  • ​​doQuery方法​​
MyBatis源碼-解讀Executor的三個實作類之SimpleExecutor(簡單執行器)

Pre

​​MyBatis源碼-深入了解MyBatis Executor的設計思想​​

工程部分見

​​MyBatis源碼- SqlSession門面模式 & selectList 源碼解析​​

MyBatis源碼-解讀Executor的三個實作類之SimpleExecutor(簡單執行器)

實際中,我們都是面向SqlSession程式設計的,不會直接調用Executor來執行業務邏輯,這裡我們僅僅是為了深入了解下Executor體系架構才這麼搞的,切記。

Executor 執行器

MyBatis源碼-解讀Executor的三個實作類之SimpleExecutor(簡單執行器)

接口繼承關系

MyBatis源碼-解讀Executor的三個實作類之SimpleExecutor(簡單執行器)

這裡我們重點看下Executor的 三個實作子類。

分别是:SimpleExecutor(簡單執行器)、ReuseExecutor(重用執行器)、BatchExecutor(批處理執行器)。

SimpleExecutor(簡單執行器)

入門小demo

package com.artisan;

import com.artisan.bean.User;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.SimpleExecutor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.transaction.jdbc.JdbcTransaction;
import org.junit.Test;

import java.sql.SQLException;
import java.util.List;

/**
 * @author 小工匠
 * @version v1.0
 * @create 2020-06-14 16:36
 * @motto show me the code ,change the word
 * @description
 **/

public class ExecutorTest extends BaseTest {


    private MappedStatement ms;
    private JdbcTransaction jdbcTransaction;

    @Test
    public void test() throws SQLException {
        // 通過factory.openSession().getConnection()執行個體化JdbcTransaction ,用于建構SimpleExecutor
        jdbcTransaction = new JdbcTransaction(factory.openSession().getConnection());
        // 映射SQL
        ms = configuration.getMappedStatement("com.artisan.UserMapper.selectByid");

        // 執行個體化SimpleExecutor
        SimpleExecutor simpleExecutor = new SimpleExecutor(configuration, jdbcTransaction);
        // 調用doQuery執行查詢
        List<User> userList = simpleExecutor.doQuery(ms, 1, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER, ms.getBoundSql(1));
        System.out.println(userList.get(0));
    }

}      
MyBatis源碼-解讀Executor的三個實作類之SimpleExecutor(簡單執行器)

有了整體的了解以後,我們拆分來看下SimpleExecutor是如何工作的

執行個體化SimpleExecutor

首先我們要執行個體化一個SimpleExecutor ,看下SimpleExecutor的源碼

兩個參數

public SimpleExecutor(Configuration configuration, Transaction transaction) {
    super(configuration, transaction);
  }      
MyBatis源碼-解讀Executor的三個實作類之SimpleExecutor(簡單執行器)

使用JdbcTransaction 即可

jdbcTransaction = new JdbcTransaction(factory.openSession().getConnection());      

doQuery方法

執行個體化完成以後,執行方法調用doQuery

@Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    .......
  }      

我們可以看到這個方法是 @Override 重寫父類的方法 ,去它的父類BaseExecutor看下該方法

BaseExecutor##doQuery

protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException;      

抽象方法 泛型支援

我們知道MyBatis Executor 有3個子類,父類中的抽象方法doQuery其實就是讓子類去重寫,實作不同的功能。

SimpleExecutor 、ReuseExecutor 、BatchExecutor 都是繼承 BaseExecutor, 重寫doQuery來實自身的特色功能 。

參數解讀

  • MappedStatement : 映射SQL
  • Object parameter : SQL中的動态參數
  • RowBounds:分頁用的,預設不分頁 RowBounds.DEFAULT , 可參考 ​

    ​org.apache.ibatis.session.RowBounds​

  • ResultHandler: 自定義處理傳回結果 ,不使用寫 ​

    ​Executor.NO_RESULT_HANDLER​

  • BoundSql : 綁定的SQL

入參講完了,我們來看下doQuery方法都做了些什麼工作

@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();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }      
  1. 擷取大管家 Configuration
  2. 每次都要newStatementHandler ,這個StatementHandler 後面我們重點将,是專門處理JDBC的
  3. prepareStatement --> BaseStatementHandler #prepare 方法
  4. 調用SimpleStatementHandler#query

我們看下執行過程的日志輸出

17:50:42,538 DEBUG com.artisan.UserMapper.selectByid:143 - ==>  Preparing: select * from users where id = ? 
17:50:42,739 DEBUG com.artisan.UserMapper.selectByid:143 - ==> Parameters: 1(Integer)
17:50:42,808 DEBUG com.artisan.UserMapper.selectByid:143 - <==      Total: 1
User{id=1, name='artisan', age='11', sex='male', emal='[email protected]', phoneNumber='12345', createTime=Thu Jun 04 08:00:00 CST 2020}      

預編譯 —執行SQL ----擷取傳回結果

我們加上兩行代碼在執行一遍

List<User> userList2 = simpleExecutor.doQuery(ms, 1, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER, ms.getBoundSql(1));
  System.out.println(userList2.get(0));      
MyBatis源碼-解讀Executor的三個實作類之SimpleExecutor(簡單執行器)

可以發現,相同的SQL 每次調用 都會預編譯 ,我們期望的結果是 相同的SQL隻要編譯一次即可,那SimpleExecutor不支援,那怎麼辦呢

繼續閱讀