Pre
MyBatis源碼-深入理解MyBatis Executor的設計思想
工程部分見
MyBatis源碼- SqlSession門面模式 & selectList 源碼解析
實際中,我們都是面向SqlSession編程的,不會直接調用Executor來執行業務邏輯,這裏我們僅僅是爲了深入瞭解下Executor體系架構才這麼搞的,切記。
Executor 執行器
接口繼承關係
這裏我們重點看下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
* @blog https://artisan.blog.csdn.net/
* @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));
}
}
有了整體的瞭解以後,我們拆分來看下SimpleExecutor是如何工作的
實例化SimpleExecutor
首先我們要實例化一個SimpleExecutor ,看下SimpleExecutor的源碼
兩個參數
public SimpleExecutor(Configuration configuration, Transaction transaction) {
super(configuration, transaction);
}
使用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);
}
}
- 獲取大管家 Configuration
- 每次都要newStatementHandler ,這個StatementHandler 後面我們重點將,是專門處理JDBC的
- prepareStatement --> BaseStatementHandler #prepare 方法
- 調用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));
可以發現,相同的SQL 每次調用 都會預編譯 ,我們期望的結果是 相同的SQL只要編譯一次即可,那SimpleExecutor不支持,那怎麼辦呢
Executor 的另外一個實現類 ReuseExecutor 支持該功能 。 下篇博文我們來瞅瞅ReuseExecutor