猿问

在全局事务中运行的本地事务的正确含义是什么?

我是 JTA 的新手,目前正在深入研究其规范。我还创建了一些示例项目来更快地深入研究这个主题。我使用 IBM WebSphere 9 作为运行时。

我创建了一个由 EJB 和 MDB 组成的简单项目。这个想法是我向队列发送一些 JMS,然后 MDB 获取此消息,处理它并使用本地接口调用 EJB(MDB 和 EJB 位于同一个 EAR)。反过来,EJB 将处理传入的对象,并通过XA数据源使用 JDBC 将其写入 Oracle 数据库。

MDBonMessage()方法有一个TransactionAttributeType.NOT_SUPPORTED定义,正如 JTA 所说,它应该在事务上下文之外运行。

process()从MDB调用的EJB的方法没有任何TransactionAttributes定义,因为它来自JTA它应该有一个默认值,即TransactionAttributeType.REQUIRES_NEW. 因此,如果我没有错,它会在被调用时启动一个新的全局 TX,还是我错了?

我还创建了一个简单的 DAO 类,它获取一个 JDBC 连接并运行语句来存储从 EJB 接收到的数据。它位于 EJB 旁边的包中的普通 Java 类中。

当我尝试运行项目时会出现问题,更具体地说,当我尝试从数据源获取连接时会出现问题。由于我使用的是 XA 数据源,因此发生XAER_PROTO异常:

[7/17/18 16:32:52:771 GMT+01:00] 000001b4 WSRdbXaResour E DSRA0304E:发生 XAException。XAException 内容和详细信息是:
XA 错误是:-6 XA 错误消息是:在不正确的上下文中调用了例程。Oracle > 错误代码是:24776 Oracle 错误消息是:内部 XA 错误

经过一段时间调查这个问题,我发现这个问题可能与 JTA 规范中的这个陈述有关:

3.4.7 本地和全球交易

...

当使用同一个连接执行本地和全局事务时,以下规则适用:

• 在连接中启动全局事务之前,必须提交(或回滚)本地事务。

• 在启动任何本地事务之前,必须将全局事务与连接解除关联。

所以我的问题是:

  1. 是一个 EJB 方法,TransactionAttributeType.REQUIRES_NEW在 JTA 方面用 a 注释启动一个全局 TX 吗?

  2. 我的假设是否正确,即从数据源检索新的 JDBC 连接会根据 JTA 启动新的本地事务?

  3. 如果以上都是正确的,那么实际上是否可以在全局 TX 下的 EJB 中使用普通 JDBC?或者我应该只从非事务性 EJB 调用与 JDBC 相关的方法?

  4. 我应该认为上述方法是错误的吗?

  5. 我应该使用更抽象的 JTA 接口来处理数据库而不是使用“普通”的 JDBC 方法吗?如果是这样,那么哪种方式更可取?


RISEBY
浏览 184回答 1
1回答

HUWWW

回答您的问题:1. EJB 方法,用 TransactionAttributeType.REQUIRES_NEW 注释是否会根据 JTA 启动全局 TX?是的,REQUIRES_NEW 会导致容器启动一个新的全局事务。2. 我的假设是否正确,即从数据源检索新的 JDBC 连接会根据 JTA 启动新的本地事务?你几乎是对的。检索 JDBC 连接实际上并不启动事务。但是,在没有全局事务的情况下,对 JDBC 连接(例如 createStatement、execute 等)执行有意义的工作会启动本地事务。3. 如果以上都是正确的,那么在全局 TX 下是否可以在 EJB 中使用普通 JDBC?或者我应该只从非事务性 EJB 调用与 JDBC 相关的方法?无论是否在全局事务下,普通 JDBC 对 EJB 都是完全有效的。4. 我应该认为上述方法是错误的吗?您描述的场景应该可以正常工作。很可能有一些额外的细节导致了问题,可能与订购或不提交有关。5. 我应该使用更抽象的 JTA 接口来处理数据库,而不是使用“普通”的 JDBC 方法吗?如果是这样,那么哪种方式更可取?我建议调试您所看到的问题的原因。如果我理解你描述的场景,你调用 getConnection 两次,第一次是在一个全局事务中因为 EJB 标记为 REQUIRES_NEW,随后,在该方法返回并且事务提交之后,你第二次调用 getConnection 并使用它是一个新的本地交易。您应该澄清哪个 getConnection 尝试失败,是否还有其他尝试,如果可能,请从您的源代码中发布片段。您还应该发布错误的完整堆栈。缺少这些,这意味着您得到的答案更有可能是猜测而不是答案。例如,考虑到 Oracle 错误,我可以猜测您可能在尝试在全局事务中使用连接之前从未提交的本地事务中额外使用了该连接。还需要注意的是,在应用服务器中,连接被池化,因此先前的使用可能来自未在本地事务中提交连接的不同线程。应用程序服务器会尽最大努力检测此类事件并为您清理,但并非总是如此。因此,对于在某些情况下可能不会提交/回滚的任何连接,您还需要查看其他连接使用情况。
随时随地看视频慕课网APP

相关分类

Java
我要回答