MyBatis源码-解读Executor的三个实现类之ReuseExecutor(重用执行器)

2021-08-17 15:24:15 浏览数 (1)

Pre

MyBatis源码-深入理解MyBatis Executor的设计思想

工程部分见 MyBatis源码- SqlSession门面模式 & selectList 源码解析

实际中,我们都是面向SqlSession编程的,不会直接调用Executor来执行业务逻辑,这里我们仅仅是为了深入了解下Executor体系架构才这么搞的,切记。


Executor 执行器


接口继承关系

这里我们重点看下Executor的 三个实现子类。

分别是:SimpleExecutor(简单执行器)、ReuseExecutor(重用执行器)、BatchExecutor(批处理执行器)。


ReuseExecutor(重用执行器)

回归下JDBC中的 Statement , 再和MyBatis 所封装的 对比一下

PreparedStatement 支持预编译参数

MyBatis的ReuseExecutor就是利用了JDBC Statement的这个特点 来处理的。

入门小demo

代码语言:javascript复制
    @Test
    public void testReuseExecutor() throws SQLException {
        // 通过factory.openSession().getConnection()实例化JdbcTransaction ,用于构建ReuseExecutor
        jdbcTransaction = new JdbcTransaction(factory.openSession().getConnection());
        // 映射SQL
        ms = configuration.getMappedStatement("com.artisan.UserMapper.selectByid");

        // 实例化ReuseExecutor
        ReuseExecutor executor = new ReuseExecutor(configuration, jdbcTransaction);
        // 调用doQuery执行查询
        List<User> userList = executor.doQuery(ms, 1, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER, ms.getBoundSql(1));
        System.out.println(userList.get(0));


        List<User> userList2 = executor.doQuery(ms, 1, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER, ms.getBoundSql(1));
        System.out.println(userList2.get(0));

    }

执行结果

可以看到 相同的SQL语句 会缓存对应的PrepareStatement , 缓存的生命周期: 会话有效期


源码实现

Key 是 sql , Value 是 Statement

执行过程:

executor.doQuery ----> prepareStatement(handler, ms.getStatementLog())

---------> 见下方源码

代码语言:javascript复制
  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    BoundSql boundSql = handler.getBoundSql();
    String sql = boundSql.getSql();
    if (hasStatementFor(sql)) {
      stmt = getStatement(sql);
      applyTransactionTimeout(stmt);
    } else {
      Connection connection = getConnection(statementLog);
      stmt = handler.prepare(connection, transaction.getTimeout());
      putStatement(sql, stmt);
    }
    handler.parameterize(stmt);
    return stmt;
  }

先判断本地缓存statementMap是否有数据,有的话从statementMap获取,没有的话建立Statement,并存入本地缓存statementMap 。

注意这个缓存的声明周期 是仅限于本次会话。 会话结束后,这些缓存都会被销毁掉。

区别于SimpleExecutor的实现,多了个本地缓存。 推荐使用ReuseExecutor 。


0 人点赞