我有三个在事务边界内执行的事务服务(stratTransaction或开始事务)。所有这三个服务分别使用不同的连接(No_Transaction,Local_Transaction和XA_Transaction)进行处理。现在我想知道,当我启动一个事务(使用javax.transaction.TransactionManager)并在事务边界内运行这三个服务时,我可以看到使用NO和LOCAL事务的服务能够将数据插入表中。现在,我将使用Service XA在列中插入比表约束更多的数据(并且我知道它应该会失败)并调用提交(如果有任何失败,还会执行回滚过程)。现在我在NO和Local连接表的表中有数据,而XA连接表没有任何数据。现在:
我想知道,当事务在某一时刻失败时,应该回滚所有表中的所有数据,还是只回滚XA Service的数据?
我也想知道:我所知道的“交易”是原子传输数据的过程。那么,为什么连接创建包括定义可以由连接执行的事务类型,这不是事务的属性吗?
我也想知道为什么我们必须在连接属性中定义事务类型,而在开始事务处理时必须定义事务类型,并且事务管理器必须执行给定的事务类型。
提前致谢。
最佳答案
让我们从最简单的事务模式开始,并增加复杂性。
无交易
“无交易”连接是指不“提交”或“回滚”数据(例如发送电子邮件)的连接。将邮件对象传递到电子邮件服务器后,它将被发送给收件人,并且没有任何恳求将再次使邮件返回。几乎就像每个 call 在 call 返回时都已提交一样。这种连接的示例包括与SMTP,SMS网关,打印机等的连接。
我相信,如果您已启用自动提交功能,则可以以这种方式使用数据库连接,但这引出了一个问题,即为什么首先要拥有完整的ACID数据库...
“正常”交易
普通连接(例如,到SQL数据库的连接)可以在内部缓冲区中存储一系列状态更改命令。完成所有操作后,所有操作均显示为OK,然后将更改的整个缓冲区写入数据存储,其他连接可以看到更改。如果在提交之前甚至在提交过程中出了问题,则可以放弃整个更改集(回滚)。
这种连接的一个关键限制是缓冲区的范围-缓冲区是连接本身的一部分。换句话说,只有通过连接,您才能写入缓冲区。
应用程序服务器的重要职责是管理这些连接。当您要求连接池为您提供连接时,您每次都会神奇地获得相同的连接(在一个事务中)。即使当一个EJB调用另一个EJB或当EJB调用资源适配器时也是如此(假设您使用REQUIRES_TRANSACTION语义。您可以使用REQUIRES_NEW覆盖它)。这种行为意味着一个Web请求可以进行多个EJB调用,每个EJB调用都可以与多个实体Bean交互,并且所有数据操作都在具有单个内部缓冲区的单个连接上进行。它将全部一起提交或回滚。
具有多个连接的事务
当您只有一个数据库时,这非常好-但是(根据定义),如果要与单独的数据库实例通信(例如,在不同的计算机上),则需要单独的连接。那会发生什么呢?您的EJB事务最终与多个连接相关联-每个连接到一个唯一的数据库。除了在以下情况下,这似乎运行良好:
这是一场灾难-您已在数据库A中提交了事务,并且现在无法回滚。但是,事务(和整个EJB)在数据库B上回滚。
(有趣的是,您的示例与此几乎完全相同-您已将数据提交给no事务和常规事务,但未提交给XA事务-这三个连接中的最后)
XA交易
这就是XA出现的地方。它提供逻辑来协调针对不同数据源提交的事务,并模拟多个数据源上的单个事务。 XA提交由事务协调器管理的“两阶段提交”,事务协调器管理XA事务中共同选择的多个XA连接。统筹人
请注意,如果阶段2中出现问题(例如,部分网络崩溃或在阶段1和阶段2之间关闭数据库之一的电源),则两阶段提交可能会失败。
因为XA连接的行为与普通连接有很大不同,所以它通常需要与非XA ConnectionFactory不同的ConnectionFactory对象,该对象实例化不同的对象实例。另外,XA ConnectionFactory需要XA事务协调器的配置参数,例如XA事务超时,这是普通事务属性之外的。
另一个限制:只有XA ConnectionFactory创建的Connections可以加入XA Transaction和关联的两阶段提交。您可以使XA和非XA连接都参与单个Application Server事务,但是整个事务不能像单个事务一样可靠地提交/回滚(如上所述)。
具体答案
如果在应用程序服务器尝试提交之前事务失败(例如,您的EJB获得NPE或您有意回滚),则每个连接都将得到回滚,并且所有连接都应符合您的期望。
但是,如果事务在提交逻辑中失败(例如,数据库约束),则事务管理器将尝试回滚所有内容;否则,事务将失败。如果已经提交了非XA连接,则不会发生这种情况。
XA连接使用与普通连接不同的库和协议(protocol),因为该连接本身需要与XA事务协调器进行通信。普通连接不会这样做。
因为XA连接使用不同的代码,所以与普通连接相比,连接池需要加载不同的类。这就是为什么连接池(不是连接)属性不同的原因。
关于database - 这是交易的正确行为吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13927968/