mybatis源码解析(4)
来源:互联网 发布:pyqt linux 安装 arm 编辑:程序博客网 时间:2024/05/01 03:05
Executor的query和doQuery
sorry,好久没更新了,今天有时间,就多写点吧!
上次讲到,在DefaultSqlSession中的selectList方法,调用了executor的query方法。但这个query的方法具体是怎么实现的呢?这节来分析这个。
首先我看来看看这个executor究竟是那个实现类。这就要追溯到创建executor的地方了。
位置在
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); final Executor executor = configuration.newExecutor(tx, execType); return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
进入到configuration中的newExecutor方法
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
从中可以看到,由于我们用的是默认的executorType,所以应该创建的是SimpleExecutor,并且我们没有关闭cacheEnable,所以会在executor外面包一层CachingExecutor.
public CachingExecutor(Executor delegate) { this.delegate = delegate; delegate.setExecutorWrapper(this); }
这是CachingExecutor的构造方法。由此可见delegate对象就是SimpleExecutor(在这个场景而言,其他情况为相对应的Executor)
那我们再回过头来看executor的query方法。
这里的query实现方法应该是cachingExecutor的query方法。
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameterObject); CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql); return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
第一个参数ms上一节有提到,是所要执行sql的各项配置环境。第二个参数是执行sql的参数,第三个是selectList是的偏移量和大小的设置。最后一个是对返回结果的处理方法。
看这个方法的逻辑。从ms中拿出BoundSql,boundSql中包括了sql的内容(select XX from XXX where XX=?之类的)已经sql的所需参数的信息。
再通过这些参数创建一个缓存的key,然后根据这些属性再继续调用包含key的query方法。
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) { flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, parameterObject, boundSql); @SuppressWarnings("unchecked") List<E> list = (List<E>) tcm.getObject(cache, key); if (list == null) { list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks } return list; } } return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
这个方法也比较简单,先去取缓存,取得到就去缓存拿,取不到就调用真正的执行器去执行sql。(这里的缓存是二级缓存,暂且不讲)
看到这个delegate的query方法就知道去执行了SimpleExecutor里的query方法了。但实际上SimpleExecutor是没有query方法的,这里执行的query方法是其父类BaseExecutor的query方法。
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 (closed) throw new ExecutorException("Executor was closed."); if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { queryStack++; list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } deferredLoads.clear(); // issue #601 if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { clearLocalCache(); // issue #482 } } return list; }
看到这个方法又去拿了一次缓存,其实这里是一级缓存,也暂且不讲。这里的真正实现是queryFromDatabase的doQuery方法,而这个doquery方法,就是SimpleExecutor里的方法了。
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.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } }
这里拿到Configuration然后再创建statement,statement是什么,参考第一节的jdbc连接数据库方法。(是不是感觉接近真相了)
然后执行handler的query方法。
这个方法具体又是怎么操作的呢?下节分析。
- mybatis源码解析(4)
- (一)MyBatis源码解析之配置文件
- (二)MyBatis源码解析之配置文件
- (三)MyBatis源码解析之配置文件
- (四)MyBatis源码解析之SqlSession
- mybatis源码解析(二)生成SqlSessionFactory
- mybatis源码解析(三)SqlSession
- Mybatis SqlSessionTemplate 源码解析
- mybatis源码初步解析
- MyBatis源码解析一
- Mybatis SqlSessionTemplate 源码解析
- Mybatis SqlSessionTemplate 源码解析
- mybatis源码解析
- Mybatis源码解析 KeyGenerator
- mybatis源码解析
- Mybatis SqlSessionTemplate 源码解析
- Mybatis SqlSessionTemplate 源码解析
- mybatis源码解析
- WINDOWS7 : Oracle Database 11g 未在当前操作系统中经过认证
- 求JAVA初级开发职位
- enable_shared_from_this模板类使用完全解析
- wince7下如何添加一个新的驱动程序
- 在window7操作系统上安装苹果系统MAC虚拟机工具选用体验
- mybatis源码解析(4)
- AJAX利用JSONP方式实现跨域数据传递
- 老树开新花,工作3年了第一次csdn开写博客,记录一下~~
- HippoEDIT v1 60 11 x64-LAXiTY
- .net微信公众号开发——基础接口
- 对于ssh快速入门的问题
- 程序员真相
- HDU 3450 Counting Sequences
- 安卓信鸽推送