mybatis源码阅读-执行器Executor(四)

说明

前面二看到了 sqlSession最终是找到MapperStatement然后委托给Executer执行的 Executer到底做了什么

接口定义

public interface Executor {
    ResultHandler NO_RESULT_HANDLER = null;

    int update(MappedStatement var1, Object var2) throws SQLException;

    <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, CacheKey var5, BoundSql var6) throws SQLException;

    <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException;

    <E> Cursor<E> queryCursor(MappedStatement var1, Object var2, RowBounds var3) throws SQLException;

    List<BatchResult> flushStatements() throws SQLException;

    void commit(boolean var1) throws SQLException;

    void rollback(boolean var1) throws SQLException;

    CacheKey createCacheKey(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4);

    boolean isCached(MappedStatement var1, CacheKey var2);

    void clearLocalCache();

    void deferLoad(MappedStatement var1, MetaObject var2, String var3, CacheKey var4, Class<?> var5);

    Transaction getTransaction();

    void close(boolean var1);

    boolean isClosed();

    void setExecutorWrapper(Executor var1);
}

类图

Executor各个实现

ClosedExecutor

org.apache.ibatis.executor.loader.ResultLoaderMap 中的一个内部静态类

 private static final class ClosedExecutor extends BaseExecutor {
        public ClosedExecutor() {
            super((Configuration)null, (Transaction)null);
        }

        public boolean isClosed() {
            return true;
        }

        protected int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
            throw new UnsupportedOperationException("Not supported.");
        }

        protected List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
            throw new UnsupportedOperationException("Not supported.");
        }

        protected <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
            throw new UnsupportedOperationException("Not supported.");
        }

        protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
            throw new UnsupportedOperationException("Not supported.");
        }
    }

没有具体实现  我们不会用到

简单SimpleExecutor

每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。(可以是Statement或PrepareStatement对象)

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

        int var6;
        try {
            //获得configuration
            Configuration configuration = ms.getConfiguration();
            //根据configuration获得对应的StatementHandler 后面讲
            StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler) null, (BoundSql) null);
            stmt = this.prepareStatement(handler, ms.getStatementLog());
            var6 = handler.update(stmt);
        } finally {
            //释放Statement
            this.closeStatement(stmt);
        }

        return var6;
    }
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Connection connection = this.getConnection(statementLog);
        Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
        handler.parameterize(stmt);
        return stmt;
    }
}

可以看到finally会关闭Statement

复用ReuseExecutor

Statement会根据sql语句进行保存 相同sql语句达到复用 避免多次编译

public class ReuseExecutor extends BaseExecutor {
    //保存Statement key为sql语句
    private final Map<String, Statement> statementMap = new HashMap();

    public ReuseExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }

    public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
        //构建Statemetn
        Statement stmt = this.prepareStatement(handler, ms.getStatementLog());
        return handler.update(stmt);
    }
    public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
        Iterator i$ = this.statementMap.values().iterator();

        while(i$.hasNext()) {
            Statement stmt = (Statement)i$.next();
            this.closeStatement(stmt);
        }
        //清空缓存
        this.statementMap.clear();
        return Collections.emptyList();
    }

    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        BoundSql boundSql = handler.getBoundSql();
        //获得sql语句
        String sql = boundSql.getSql();
        Statement stmt;
        //判断是否有缓存 如果有重缓存取
        if (this.hasStatementFor(sql)) {
            stmt = this.getStatement(sql);
            this.applyTransactionTimeout(stmt);
        } else {
            Connection connection = this.getConnection(statementLog);
            //如果没有创建Statement 并仿佛缓存
            stmt = handler.prepare(connection, this.transaction.getTimeout());
            this.putStatement(sql, stmt);
        }

        handler.parameterize(stmt);
        return stmt;
    }

    private boolean hasStatementFor(String sql) {
        try {
            return this.statementMap.keySet().contains(sql) && !((Statement)this.statementMap.get(sql)).getConnection().isClosed();
        } catch (SQLException var3) {
            return false;
        }
    }

    private Statement getStatement(String s) {
        return (Statement)this.statementMap.get(s);
    }

    private void putStatement(String sql, Statement stmt) {
        this.statementMap.put(sql, stmt);
    }
}

Statement什么时候释放 doFlushStatements为父类的抽象方法 父类再rollback和commit 会调用doFlushStatements()(模板方法模式)

BaseExecutor代码

    public void commit(boolean required) throws SQLException {
        if (this.closed) {
            throw new ExecutorException("Cannot commit, transaction is already closed");
        } else {
            this.clearLocalCache();
//会里面会调用this.doFlushStatements()
this.flushStatements(); if (required) { this.transaction.commit(); } } }

批量BatchExecutor

public class BatchExecutor extends BaseExecutor {
    public static final int BATCH_UPDATE_RETURN_VALUE = -2147482646;
    private final List<Statement> statementList = new ArrayList();
    private final List<BatchResult> batchResultList = new ArrayList();
    //上一次sql
    private String currentSql;
    //上一次Statement
    private MappedStatement currentStatement;

    public BatchExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }

    public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
        Configuration configuration = ms.getConfiguration();
        StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null);
        BoundSql boundSql = handler.getBoundSql();
        String sql = boundSql.getSql();
        Statement stmt;
        //当前sql语句是否与上一次sql语句一样 如果一样同时 当前Statement是否与上一次Statement一样
        if (sql.equals(this.currentSql) && ms.equals(this.currentStatement)) {
            //取出最后一个Statement
            int last = this.statementList.size() - 1;
            stmt = (Statement)this.statementList.get(last);
            this.applyTransactionTimeout(stmt);
            handler.parameterize(stmt);
            //获得BatchResult 增加参数inset table value('1111','2222',....)
            BatchResult batchResult = (BatchResult)this.batchResultList.get(last);
            batchResult.addParameterObject(parameterObject);
        } else {
            //不存在在则新增Statement
            Connection connection = this.getConnection(ms.getStatementLog());
            stmt = handler.prepare(connection, this.transaction.getTimeout());
            handler.parameterize(stmt);
            this.currentSql = sql;
            this.currentStatement = ms;
            this.statementList.add(stmt);
            this.batchResultList.add(new BatchResult(ms, sql, parameterObject));
        }
        // 将sql以addBatch()的方式,添加到Statement中(该步骤由StatementHandler内部完成)
        handler.batch(stmt);
        return -2147482646;
    }

    /**
     * 负责批量执行
     * @param isRollback
     * @return
     * @throws SQLException
     */
    public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
        boolean var17 = false;

        Statement stmt;
        List var21;
        Iterator i$;
        label168: {
            ArrayList var20;
            try {
                var17 = true;
                ArrayList results = new ArrayList();
                if (isRollback) {
                    var21 = Collections.emptyList();
                    var17 = false;
                    break label168;
                }

                int i = 0;

                //批量执行
                for(int n = this.statementList.size(); i < n; ++i) {
                    stmt = (Statement)this.statementList.get(i);
                    this.applyTransactionTimeout(stmt);
                    BatchResult batchResult = (BatchResult)this.batchResultList.get(i);

                    try {
                        batchResult.setUpdateCounts(stmt.executeBatch());
                        MappedStatement ms = batchResult.getMappedStatement();
                        List<Object> parameterObjects = batchResult.getParameterObjects();
                        KeyGenerator keyGenerator = ms.getKeyGenerator();
                        if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
                            Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator)keyGenerator;
                            jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
                        } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) {
                            Iterator i$ = parameterObjects.iterator();

                            while(i$.hasNext()) {
                                Object parameter = i$.next();
                                keyGenerator.processAfter(this, ms, stmt, parameter);
                            }
                        }
                    } catch (BatchUpdateException var18) {
                        StringBuilder message = new StringBuilder();
                        message.append(batchResult.getMappedStatement().getId()).append(" (batch index #").append(i + 1).append(")").append(" failed.");
                        if (i > 0) {
                            message.append(" ").append(i).append(" prior sub executor(s) completed successfully, but will be rolled back.");
                        }

                        throw new BatchExecutorException(message.toString(), var18, results, batchResult);
                    }

                    results.add(batchResult);
                }

                var20 = results;
                var17 = false;
            } finally {
                if (var17) {
                    Iterator i$ = this.statementList.iterator();

                    while(i$.hasNext()) {
                        Statement stmt = (Statement)i$.next();
                        this.closeStatement(stmt);
                    }

                    this.currentSql = null;
                    //释放
                    this.statementList.clear();
                    //释放
                    this.batchResultList.clear();
                }
            }

            i$ = this.statementList.iterator();
            //释放
            while(i$.hasNext()) {
                stmt = (Statement)i$.next();
                this.closeStatement(stmt);
            }

            this.currentSql = null;
            this.statementList.clear();
            this.batchResultList.clear();
            return var20;
        }

        i$ = this.statementList.iterator();

        while(i$.hasNext()) {
            stmt = (Statement)i$.next();
            this.closeStatement(stmt);
        }

        this.currentSql = null;
        this.statementList.clear();
        this.batchResultList.clear();
        return var21;
    }
}

if (sql.equals(this.currentSql) && ms.equals(this.currentStatement))看出 如果sql一样同时是连续的 则是使用同一个statement
比如 aabb生成2个statement abba会生成三个statement  主要作用是减少sql预编译时间

缓存CachingExecutor

public class CachingExecutor implements Executor {
    private Executor delegate;
    public CachingExecutor(Executor delegate) {
        this.delegate = delegate;
        delegate.setExecutorWrapper(this);
    }

    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        //根据sql和参数算出缓存key
        CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
        return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }

    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        //是否有缓存
        Cache cache = ms.getCache();
        if (cache != null) {
            //是否清除缓存
            this.flushCacheIfRequired(ms);
            //是否应用缓存
            if (ms.isUseCache() && resultHandler == null) {
                //
                this.ensureNoOutParams(ms, parameterObject, boundSql);
                //如果缓存拿不到 则通过delegate重新执行query
                List<E> list = (List)this.tcm.getObject(cache, key);
                if (list == null) {
                    list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                    this.tcm.putObject(cache, key, list);
                }

                return list;
            }
        }

        return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }

   
}

装饰者模式判断是否有缓存 如果没有则委托给delegate执行 拿到结果再将结果缓存

Executor的设置

默认为Simple

configuration配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="defaultExecutorType" value="REUSE" />
    </settings>
</configuration>

openSession

@Override
  public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
    return openSessionFromDataSource(execType, null, autoCommit);
  }
原文地址:https://www.cnblogs.com/LQBlog/p/10679265.html