zoukankan      html  css  js  c++  java
  • 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);
      }
  • 相关阅读:
    在AE中通过SDE添加图层(转)
    上一视图下一视图功能实现(C#+SuperMap Objects)
    [Python入门及进阶笔记]Python基础内置函数小结
    Javascript小球
    64位centos下安装python的PIL模块
    [Python入门及进阶笔记]Python基础集合小结
    C语言的那些小秘密之【链表(二)】
    巴斯卡三角形
    [Python入门及进阶笔记]Python基础数字处理相关模块
    C语言的那些小秘密之【链表(一)】
  • 原文地址:https://www.cnblogs.com/LQBlog/p/10679265.html
Copyright © 2011-2022 走看看