当前位置: 首页 > 知识库问答 >
问题:

java - 不明白mybatis源码中queryStack变量的作用是什么?

郎睿
2024-03-20

在阅读mybatis源码时,发现问题:

源码org.apache.ibatis.executor.BaseExecutor#query,如下:

protected int queryStack;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) {        //处理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,但是我跟代码半天,也没有发现哪里会递归。

有没有大佬讲讲啥时候这个方法会递归调用?或者是其他作用。

共有1个答案

辛弘壮
2024-03-20

首先 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() 方法,这就可能会制造出一个递归。

 类似资料:
  • Java编译器知道if语句的条件总是true,因此y总是被初始化的。正如预期的那样,没有编译错误。 但是当我把x的声明和初始化分成两行时,编译器似乎没有得到条件总是真的,y总是被初始化的。 这里也会发生同样的情况,编译器会给出精度损失错误。 同样,编译器可以理解x在b的范围内。

  • 还不起作用。所以我放弃链接,我只是编码:

  • 下面是一个链表的简单实现。我刚刚添加了相关代码。首先,我向列表中添加一些值,10,990和10000。当我搜索相同的值时,对于key=10,我得到true,但是对于key=990和key=10000得到false,尽管它应该是true。另外,如果我将第二个值从990更改为99,并搜索key=99,这一次我得到的是true。 我不确定是否使用泛型类型。我想我在那里做错了什么。因为如果我用int替换泛

  • MyBatis 3.2.8。我在SELECT中有以下代码: 当时,一切正常。但是,当时,会出现以下异常:

  • 问题内容: Q1。 Java中的condVar是什么?如果我看到下面的代码,条件变量是否一定必须在“ mutex.acquire() ”和“ mutex.release() ”块内? 我有三个正在运行的线程 myThreadA , myThreadB 和 myThreadC ,它们调用相同的函数 commonActivity() 来触发函数 myWorkReport(), 例如 Q2。 使用tim

  • 问题内容: 我正在读一本书,遇到过Java中的“影子变量”一词,但没有描述。最终,这些变量是做什么用的,以及如何实现? 问题答案: 除了提供我自己的描述之外,我可能会要求您例如在以下位置阅读它:http : //en.wikipedia.org/wiki/Variable_shadowing。了解变量的阴影后,建议您继续阅读有关覆盖/阴影方法和可见性的一般知识,以全面了解此类术语。 实际上,由于该