编程语言
首页 > 编程语言> > java-在全局事务中运行本地事务的正确含义是什么?

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

作者:互联网

我是JTA的新手,目前正深入了解其规范.我还创建了一些示例项目,以更快地深入该主题.我将IBM WebSphere 9用作运行时.

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

MDB onMessage()方法定义了TransactionAttributeType.NOT_SUPPORTED,正如JTA所说的,它应该在事务上下文之外运行.

从MDB调用的EJB的process()方法尚未定义任何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 occurred. XAException contents and details are:
The XA Error is: -6
The XA Error message is: Routine was invoked in an improper context. The Oracle > Error code is: 24776
The Oracle Error message is: Internal XA Error

经过一段时间的研究,我发现这个问题可能与JTA规范中的以下语句有关:

3.4.7 Local and Global Transactions

When using the same connection to perform both local and global
transactions, the following rules apply:

• The local transaction must be committed (or rolled back) before
starting a global transaction in the connection.

• The global transaction must be disassociated from the connection
before any local transaction is started.

所以我的问题是:

>是否是用TransactionAttributeType.REQUIRES_NEW注释的EJB方法根据JTA启动了全局TX?
>我的假设是正确的,即从数据源中检索新的JDBC连接会启动有关JTA的新本地事务?
>如果上述所有方法都正确,那么实际上可以在全局TX下在EJB中使用纯JDBC吗?或者我应该仅从非事务性EJB调用与JDBC相关的方法?
>我是否应该将上述方法视为错误的方法?
>是否应该使用更多抽象的JTA接口来处理数据库,而不要使用“普通” JDBC方法?如果是这样,那哪种方法更可取?

解决方法:

要回答您的问题:

1.是否有用TransactionAttributeType.REQUIRES_NEW注释的EJB方法根据JTA启动全局TX?

是的,REQUIRES_NEW使容器开始新的全局事务.

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

您几乎是正确的.检索JDBC连接实际上并不启动事务.但是,在没有全局事务的情况下,对JDBC连接进行有意义的工作(例如createStatement,execute等)会启动本地事务.

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

无论是否在全局事务下,纯JDBC对EJB都是完全有效的.

4.我是否应该将上述方法视为错误的方法?

您所描述的方案应该可以正常工作.最有可能导致麻烦的其他一些细节,可能与订购或未提交有关.

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

我建议您调试出现问题的原因.

如果我理解您所描述的场景,则您将两次调用getConnection,第一次是由于标记为REQUIRES_NEW的EJB在全局事务中进行的,然后在该方法返回并提交事务之后,第二次调用getConnection并将其用于新的本地交易.您应该弄清楚哪个getConnection尝试失败,是否还有其他尝试,如果可能的话,请从源代码中发布摘要.您还应该发布完整的错误堆栈.缺少这些,意味着您获得的答案比答案更可能是猜测.例如,考虑到Oracle错误,我可能会猜想您可能在本地事务中有其他先前使用过的连接,而在尝试在全局事务中使用该连接之前,它从未提交过.还应注意,在应用程序服务器中,连接被池化,因此先前的用法可能来自未在本地事务中提交连接的其他线程.应用程序服务器会尽力检测到这种情况并为您清理,但并非总是如此.因此,您还将希望查看在某些情况下可能未提交/回退的任何其他连接使用情况.

标签:jta,jdbc,websphere,ejb,java
来源: https://codeday.me/bug/20191025/1925751.html