我试图了解如何正确调用javax.transaction.xa.XAResource.recovery(int)方法。我正在处理一个手动调用XA操作且没有容器资源管理器的环境。

JavaDocs简单地说,可能存在TMSTARTRSCANTMENDRSCANTMNOFLAGS的标志值,但是没有提供使用这些标志或其组合时会发生什么的解释。

我已经对Glassfish代码进行了梳理,以了解它们可能对标志值所做的事情,但是在那里没有发现任何帮助。我看过Artemis-仅当使用单独的TMSTARTRSCAN标志时,它才会返回所有未完成的交易。 Postgres JDBC几乎相同,不同之处在于它可以将TMSTARTRSCANTMENDRSCAN耦合在一起,并且所有内容都在一个调用中返回。

我假设这些标志存在的原因是为了对结果进行某种分页,以防万一有太多未完成的事务。因此,解决此问题的正确方法是:


recover()调用TMSTARTRSCAN
recover()调用TMNOFLAGS直到结果数组为空
recover()调用TMENDRSCAN


对于上述所有调用,准备处理返回的XID值。

但是,我希望指出或解释其作用方式。

更新

正如@kayaman优美地指出我来自X / Open的XA规范一样,我可以看到我的假设可能是正确的。该标准更清楚地说明了预期的行为,但是由于数组大小期望不同,因此该标准不适用于Java实现。该标准解释了何时不调用recover(TMENDRSCAN),但是对于Java来说尚不清楚,并且不清楚是否错误地调用它可能导致异常。

最佳答案

这个JTA功能特别不直观,因为XA规范中许多底层C API的设计细微之处都转化为Java,但并非完全正确,它们在自动处理内存管理的语言中并不重要。

首先,很重要的一点是要从事务管理器(实际上调用恢复方法的组件)或资源管理器(实现该方法的组件)的角度进行操作。 Glassfish是TM,Artemis和Postgres是RM。

TM调用以迭代方式进行恢复,从TMSTARTRSCAN(打开一个新的迭代器,获取第一批结果)开始,然后有选择地跟随TMNOFLAGS(检查是否有其他结果批处理,直到返回一个空,表明已结束)并终止使用TMENDRSCAN(关闭迭代器,使RM释放其持有的项)。在实践中,可疑分支/ Xid的数量非常小,以至于它们只能形成一个批处理,因此许多TM会简单地先调用TMSTARTRSCAN,然后再直接调用TMENDRSCAN,甚至在一次调用中都执行。从理论上讲,这可能会遗漏一些不确定的分支,但通常会很好地工作,因为周期性地重复调用周期,并且在下一遍中会简单地收取任何额外费用。

RM作为稳定的游标/迭代器实现了恢复,因此它满足了在迭代过程中不会发生太大变化的要求。同时它可以选择将不确定的TX分支拆分为多个批次,例如尽量减少驱动程序中的内存使用,由于上述原因,这不是常见的优化方法。

10-06 13:03