不明白mybatis源码中queryStack变量的作用是什么?-灵析社区

momo

在阅读mybatis源码时,发现问题: 源码**org.apache.ibatis.executor.BaseExecutor#query** ,如下: protected int queryStack; public List 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 list; try { queryStack++; list = resultHandler == null ? (List) localCache.getObject(key) : null; if (list != null) { //处理Callable类型,还需要绑定IN/OUT参数 handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { //本地缓存没有结果,直接查询数据库 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } if (queryStack == 0) { // ... codeA ... } return list; } 我无法明白这个queryStack变量的意义。 通过控制流程来看: 1. 假如这段代码允许多线程并发,那么int变量一定会出现线程安全问题。 2. 假如这段代码仅允许单线程跑,那么只可能是因为存在递归的情况,才需要引用int来记录stack,但是我跟代码半天,也没有发现哪里会递归。 有没有大佬讲讲啥时候这个方法会递归调用?或者是其他作用。

阅读量:141

点赞量:0

问AI
首先 BaseExecutor 就没有设计为允许多线程并发调用,因为你看它的代码就知道一个 BaseExecutor 对象包含一个 Transaction,这样的设计表示它专属于某个数据库事务,而数据库事务的执行就是单线程的。换句话说,用户在调用 SqlSessionFactory.openSession() 方法,得到 SqlSession 对象之后,都不可以使其被多个线程访问。 其次说到 queryStack 这个变量。确实框架本身并没有直接的递归调用,但框架设计了一个扩展机制,你可以在 InterceptorChain 里面看到,框架允许用户创建自己的 Interceptor 实现类。这个实现类将会在 Configuration.newStatementHandler() 方法中被调用,而这个方法会在 BaseExecutor 的多个子类中用到。举一个例子,调用链如下: BaseExecutor#query() -> BaseExecutor#queryFromDatabase() -> BaseExecutor#doQuery() -> SimpleExecutor#doQuery() // 这里以 SimpleExecutor 为例 -> Configuration#newStatementHandler() 调用到了这里,用户创建的 Interceptor 就开始起作用了,框架无法预料用户会怎么写,如果用户在这个过程中又调用了 Executor.query() 方法,这就可能会制造出一个递归。