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='123@qq.com', 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