这是交易的正确行为吗?

0o'*_*'o0 9 database database-connection transactions commit java-ee

我有三个在事务边界内执行的事务服务(stratTransaction或begin transaction).所有三个服务分别使用不同的连接(No_Transaction,Local_Transaction和XA_Transaction)进行处理.现在我想知道,当我启动事务(使用javax.transaction.TransactionManager)并在事务边界内运行这三个服务时,我可以看到使用NO和LOCAL事务的服务能够将数据插入表中.现在我使用Service XA在列中插入超过表约束的数据(我知道它应该失败)并调用commit(如果有任何失败则返回一个回滚过程).现在我在NO和Local连接表的表中有数据,而XA连接表没有任何数据.现在:

我想知道当事务在某一时刻失败时,它会被要求从所有表中回滚所有数据,或者只是回滚XA服务的数据?

我也想知道:据我所知,"交易"是一种以原子方式传输数据的过程.那么为什么连接创建包括定义可以通过连接执行的事务类型不是事务的属性?

我还想知道为什么我们必须在连接属性中定义事务类型,而我们必须在启动转换时定义事务类型,并且事务管理器必须执行给定类型的事务.

提前致谢.

And*_*ock 4

我们先从最简单的交易模式开始,增加复杂度。

没有交易

“无事务”连接是指不“提交”或“回滚”数据(例如发送电子邮件)的连接。一旦您将消息对象传递给电子邮件服务器,它就会被发送给收件人,无论再多的恳求也无法再次取回该消息。几乎就像每个调用在调用返回时都已提交。这种连接的示例包括与 SMTP、SMS 网关、打印机等的连接。

我相信,如果您启用了自动提交,您可以以这种方式使用数据库连接,但这引出了一个问题:为什么您首先拥有一个完整的 ACID 数据库......

“正常”交易

例如与 SQL 数据库的正常连接能够在内部缓冲区中存储一系列状态更改命令。当一切都完成并且一切都显示正常时,整个更改缓冲区将写入数据存储,其他连接可以看到更改。如果在提交之前甚至期间出现问题,则可以放弃(回滚)整个更改集。

这种类型的连接的一个关键限制是缓冲区的范围 - 缓冲区是连接本身的一部分。换句话说,只有通过连接才能写入缓冲区。

应用程序服务器的一个重要职责是管理这些连接。当您要求连接池为您提供连接时,您每次都会神奇地获得相同的连接(在单个事务内)。即使一个 EJB 调用另一个 EJB 或 EJB 调用资源适配器时也是如此(假设您使用 REQUIRES_TRANSACTION 语义。您可以使用 REQUIRES_NEW 覆盖它)。此行为意味着一个 Web 请求可以多个 EJB 调用,每个 EJB 调用都可以与多个实体 Bean 交互,并且所有数据操作都发生在具有单个内部缓冲区的单个连接上。一切都将一起提交或回滚。

具有多个连接的事务

当您拥有单个数据库时,这非常有用 - 但是(根据定义)如果您与单独的数据库实例(例如在不同的计算机上)通信,则需要单独的连接。那么接下来会发生什么呢?您的 EJB 事务最终会与多个连接相关联 - 每个连接都连接到一个唯一的数据库。这看起来效果很好,除了一种情况:

  • 您有到数据库 A 的连接 A 和到数据库 B 的连接 B
  • 您在 A 和 B 上执行 DML 语句
  • 您提交 EJB 连接。现在的应用程序服务器:
    1. 提交连接 A - 成功
    2. 提交连接 B - 失败(例如约束失败)并且连接 B 回滚

这是一场灾难 - 您已在数据库 A 中提交了事务,现在无法回滚。但是,事务(以及整个 EJB)在数据库 B 上回滚。

(有趣的是,您的示例几乎与此相同 - 您将数据提交给无事务和正常事务,但不在 XA 事务中 - 三个连接中的最后一个)

XA交易

这就是 XA 的用武之地。它提供逻辑来协调针对不同数据源提交的事务,并模拟多个数据源上的单个事务。XA 通过由事务协调器管理的“两阶段提交”进行提交,该事务协调器管理增选到 XA 事务中的多个 XA 连接。协调员

  1. 通过 XA 连接向每个数据源发送一条消息,以查看是否可以提交事务:所有约束和数据库逻辑都会执行到最终提交之前的点。如果任何数据库报告故障,XA 协调器将回滚整个事务。第一阶段是几乎所有交易工作进行的阶段,因此需要相对较长的时间
  2. 当每个数据库都报告可以提交事务时,协调器向每个数据库发送一条消息以提交事务。这发生得非常快。

请注意,如果第 2 阶段出现问题(例如,部分网络崩溃或其中一个数据库在第 1 阶段和第 2 阶段之间断电),两阶段提交可能会失败。

由于 XA 连接的行为与普通连接非常不同,因此它通常需要不同的 ConnectionFactory 对象来实例化与非 XA ConnectionFactory 不同的对象实例。此外,XA ConnectionFactory 还需要 XA 事务协调器的配置参数,例如 XA 事务超时,这些参数是普通事务属性之外的。

另一个约束:只有 XA ConnectionFactory 创建的连接才能加入 XA 事务和关联的两阶段提交。您可以让 XA 和非 XA 连接参与单个应用程序服务器事务,但整个事务无法作为单个事务可靠地提交/回滚(如上所述)。

具体答案

我想知道当事务在某一时刻失败时,是否应该回滚所有表中的所有数据,或者只是应该回滚 XA 服务的数据?

如果事务在应用程序服务器尝试提交之前失败(例如,您的 EJB 获得 NPE 或您故意回滚),则每个连接都将收到回滚,并且一切都应该如您所期望的那样。

然而,如果事务在提交逻辑中失败(例如数据库约束),那么事务管理器将尝试回滚所有内容;如果非 XA 连接已提交,则不会发生这种情况。

我还想知道:据我所知,“事务”是原子传输数据的过程。那么为什么连接创建包括定义连接可以执行的事务类型,它不是事务的属性吗?

XA连接使用与普通连接不同的库和协议,因为连接本身需要与XA事务协调器进行通信。普通连接不会这样做。

我还想知道为什么我们必须在连接属性中定义事务类型,而我们必须在启动事务时定义事务类型,并且事务管理器必须执行给定类型的事务。

由于XA连接使用不同的代码,因此与普通连接相比,连接池需要加载不同的类。这就是连接池(不是连接)属性不同的原因。