映射器了解完了,sqlSession.select()实际上是Executor.query(),所以sql执行实际是executor执行的。
一、BaseExecutor
BaseExecutor是一个Executor的顶级抽象类,实现了Executor接口,定义sql执行的执行器。
模板设计模式的运用,将一部分方法逻辑延迟给子类来实现。(专业术语:钩子)
BaseExecutor有4个实现子类:
下面介绍下BaseExecutor的实现
1、变量与构造方法
/* org.apache.ibatis.executor.BaseExecutor */ protected Transaction transaction;//事务 protected Executor wrapper;//一个指向自己(this)的指针 protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads; //mybatis的一级缓存 protected PerpetualCache localCache; protected PerpetualCache localOutputParameterCache; //configuration对象 protected Configuration configuration; protected int queryStack; //关闭状态哨兵 private boolean closed; protected BaseExecutor(Configuration configuration, Transaction transaction) { this.transaction = transaction; this.deferredLoads = new ConcurrentLinkedQueue<DeferredLoad>(); this.localCache = new PerpetualCache("LocalCache"); this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache"); this.closed = false; this.configuration = configuration; this.wrapper = this; }
2、主要方法
由于没有注释,所以方法作用不是很清楚,简单分了下类
/* org.apache.ibatis.executor.Executor */ ResultHandler NO_RESULT_HANDLER = null; /* * sql执行方法CRUD */ int update(MappedStatement ms, Object parameter) throws SQLException; <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException; <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException; <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException; /* * 跟BatchExecutor有关的方法,暂时还不知道有什么用 */ List<BatchResult> flushStatements() throws SQLException; /* * 事务相关 */ void commit(boolean required) throws SQLException; void rollback(boolean required) throws SQLException; Transaction getTransaction(); /* * 缓存相关 */ CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql); boolean isCached(MappedStatement ms, CacheKey key); void clearLocalCache(); void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType); /* * 自身状态相关 */ void close(boolean forceRollback); boolean isClosed(); void setExecutorWrapper(Executor executor);
① sql方法执行相关
/* 方法过多,选取一个方法研究 */ /* org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler) */ public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { //获取sql BoundSql boundSql = ms.getBoundSql(parameter); //创建缓存key CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); return query(ms, parameter, rowBounds, resultHandler, key, boundSql); } public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { //sql校验是否存在 ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId()); //关闭哨兵,如果executor已关闭,抛出异常 if (closed) { throw new ExecutorException("Executor was closed."); } //清除缓存(mybatis一级缓存) //queryStack == 0 :正在执行的select类型的sql的个数 //并且 mappedStatement的flushCacheRequired属性为true,对应前面<sql>中的flushCache属性默认:<select> : false ; 非<select> true if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { queryStack++; //根据cacheKey获取缓存 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { //缓存存在,由于默认preparedStatement,这里相当于空方法 handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { //数据库查询 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } if (queryStack == 0) { //延迟加载,什么时候需要延迟加载 //关联映射时,select返回的resultMap中嵌套了子select查询,延迟加载将select与嵌套的子select查询的结果resultMap关联起来。 //具体例子 订单查询的结果中嵌套订单详情查询。 for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // issue #601 deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 // 一级缓存的作用域是statement级别,清除缓存;默认的是session会话级别,不清楚缓存 clearLocalCache(); } } return list; }
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql):数据库查询
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; //正在执行的哨兵 localCache.putObject(key, EXECUTION_PLACEHOLDER); try { //抽象方法(钩子):具体实现延迟到了子类 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { localCache.removeObject(key); } //放入缓存 localCache.putObject(key, list); if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; } protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException;
查看了下BaseExecutor类,钩子方法只有4个,都是与sql执行相关的方法。
protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException; protected abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException; protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException; protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException;
这里看看各个子类是怎样执行的,还是以doQuery()方法为研究点
SimpleExecutor(默认的Executor):每创建一个statement,执行完sql后,关闭statement
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { //获取configuration对象 Configuration configuration = ms.getConfiguration(); //应用configuration的设置--<settings>标签,驼峰命名等 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); //sql执行 statement.execute() //查询结果处理resultHandler.handleResultSet();result-->resultMap(处理嵌套sql) return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } } private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; //获取连接 Connection connection = getConnection(statementLog); //创建statement,并设置sql,默认是PreparedStatement stmt = handler.prepare(connection, transaction.getTimeout()); //设置参数parameters handler.parameterize(stmt); return stmt; }
ReuseExecutor:创建一个statement,放入到一个statementMap<sql,statement>中实现statement复用,当然statement不是一直有效,会设置一个超时时间
扫描二维码关注公众号,回复:
9697301 查看本文章
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); Statement stmt = prepareStatement(handler, ms.getStatementLog()); return handler.<E>query(stmt, resultHandler); } private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; BoundSql boundSql = handler.getBoundSql(); String sql = boundSql.getSql(); if (hasStatementFor(sql)) { //statement复用 stmt = getStatement(sql); //statement有效时间 applyTransactionTimeout(stmt); } else { Connection connection = getConnection(statementLog); stmt = handler.prepare(connection, transaction.getTimeout()); putStatement(sql, stmt); } handler.parameterize(stmt); return stmt; }
BatchExecutor:创建一个statement,执行完sql,关闭statement,与SimpleExecutor不同:
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { flushStatements(); Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql); Connection connection = getConnection(ms.getStatementLog()); stmt = handler.prepare(connection, transaction.getTimeout()); handler.parameterize(stmt); return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } }
ResultLoaderMap.ClosedExecutor:
protected <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { throw new UnsupportedOperationException("Not supported."); }
1