mybatis源码分析系列(开胃菜)-mybatis中的执行器架构体系

        我们知道mybatis通过门面模式给我们提供了一个统一的增删改查的会话SqlSession。但是呢它就像服务员一样只负责点菜并不负责做菜,真正做菜的是执行器。那mybatis中有哪些执行器呢?

        mybatis中的执行器大概有这么多:Executor、CachingExecutor、BaseExecutor、SimpleExecutor、ReuseExecutor、BatchExecutor等。看起来好像很多其实很简单,咱们往下走。

        我们通过最简单的一个查询来看看这些货到底是什么关系:

List<Object> list = sqlSession.selectList("select * from t ");

        sqlSession默认实现是DefaultSqlSession,所以我们进到这个方法:

public <E> List<E> selectList(String statement) {
        return this.selectList(statement, (Object)null);
    }

        继续进到这个方法:

public <E> List<E> selectList(String statement, Object parameter) {
        return this.selectList(statement, parameter, RowBounds.DEFAULT);
    }

        继续:

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        List var5;
        try {
            MappedStatement ms = this.configuration.getMappedStatement(statement);
            //注意 这里真正干活的是this.executor 而这个executor默认实现是CachingExecutor
            var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
        } catch (Exception var9) {
            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);
        } finally {
            ErrorContext.instance().reset();
        }

        return var5;
    }

至此,我们知道了真正干活的是这个CachingExecutor。顾名思义这是个缓存相关的执行器,它就是大名鼎鼎的二级缓存执行器。里边实现了mybatis的二级缓存相关实现。但是本篇文章并不详细解释。我们进到CachingExecutor的query方法:

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        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, boundSql);
                //这里就是去查询二级缓存了
                List<E> list = (List)this.tcm.getObject(cache, key);
                if (list == null) {
                    //如果没有查询到 那么就去执行this.delegate的query方法
                    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);
    }

那么这个this.delegate是啥呢?它就是BaseExecutor,正式mybatis里边一级缓存的执行器。那么我们继续:

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
        if (this.closed) {
            throw new ExecutorException("Executor was closed.");
        } else {
            if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
                this.clearLocalCache();
            }

            List list;
            try {
                ++this.queryStack;
                //这里就是在查询一级缓存了
                list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
                if (list != null) {
                    this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
                } else {
                    //如果没有查询到 那么就真正的去查询数据库了
                    list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
                }
            } finally {
                --this.queryStack;
            }

            if (this.queryStack == 0) {
                Iterator var8 = this.deferredLoads.iterator();

                while(var8.hasNext()) {
                    DeferredLoad deferredLoad = (DeferredLoad)var8.next();
                    deferredLoad.load();
                }

                this.deferredLoads.clear();
                if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                    this.clearLocalCache();
                }
            }

            return list;
        }
    }

我们继续进到queryFromDatabase方法:

private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);

        List list;
        try {
            //进到这个方法
            list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
            this.localCache.removeObject(key);
        }

        this.localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {
            this.localOutputParameterCache.putObject(key, parameter);
        }

        return list;
    }
protected abstract <E> List<E> doQuery(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, BoundSql var5) throws SQLException;

我们发现,咦?咋是个抽象的方法呢?那么他的实现方法在哪儿呢?哈哈哈  BaseExecutor常用的有三个现实,正是SimpleExecutor ReuseExecutor BatchExecutor。通过名字也能看出来这个仨分别是简单 重用和批处理执行器。具体的操作数据库封装JDBC都是他们干的。行棋至此,我们mybatis中的执行器整体架构已经出来了,让我们画个图来总结一下吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值