两阶段提交/共享事务

时间:2020-03-06 14:19:41  来源:igfitidea点击:

场景是这个

我们有两个应用程序A和B,它们都在单独的数据库(Oracle 9i)事务中运行

应用程序A将一些数据插入数据库,然后调用应用程序B
应用程序B将一些数据插入数据库中,这些数据(通过外键)与A的数据相关。向应用程序A返回一个" ID"
应用程序A使用ID插入其他数据,包括来自B的ID

现在,由于它们是独立的事务,但是两者都依赖于彼此的数据,因此我们需要在对每个应用程序的调用之间进行提交。当然,如果出现任何问题,回滚将非常困难。

我们将如何以最少的代码重构来解决此问题。当然,这是SOA世界中的常见问题吗?

    • -更新 - - - -

我无法在Oracle 9i中找到任何东西,但是Oracle 11g提供了DBMS_XA,其功能完全符合我的要求。

解决方案

我们有三种选择:

  • 重新设计应用程序,这样就不会有两个不同的过程(都具有数据库连接)写入数据库并将其滚动到单个应用程序中。
  • 创建用于处理A和B的所有数据库事务的应用程序C。
  • 滚动自己的两阶段提交。应用程序C充当协调器。 C向A和B发出信号,询问他们是否准备好提交。 A和B进行处理,并以" ready"或者" fail"答复对C进行响应(请注意,C上应该有一个超时以避免在一个进程挂起或者死掉时无限等待)。如果两个人都准备好答复,则C告诉他们进行提交。否则,它将发送回滚信号。

请注意,如果应用程序A依赖于应用程序B的外键(我们未声明,因此可能不是问题),则选项3可能会遇到问题。 Oracle的读取一致性可能会阻止这种情况的发生,因为应用程序A的事务将在应用程序B之前开始。这只是一个警告。

我们可以将来自应用程序A的数据插入"临时"区域,以便应用程序B可以同时插入A和B,而无需在两个应用程序中进行太多更改。它不是特别优雅,但可以达到目的。

在另一种情况下,我们可以在数据中添加一个"确认"标志字段,该标志字段将在整个过程成功运行后进行更新。如果它在某一时刻失败,则可能更容易跟踪需要回滚的记录(实际上是删除)。

App_A =={0}=>               database # App_A stores information for App_B
App_A ------> App_B                  # App_A starts App_B
              App_B <={0}== database # App_B retrieves the information
              App_B =={1}=> database # App_B stores more informaion
App_A <={2}== App_B                  # App_B returns 'ID' to App_A
App_A ={2,3}>               database # App_A stores 'ID' and additional data

是我还是应用程序B本质上只是A的子例程。我的意思是,应用程序B在A询问之前不执行任何操作,而应用程序A在B返回ID之前不执行任何操作。这意味着将它们放在不同的应用程序甚至单独的线程中几乎没有任何意义。

我喜欢介绍的两种解决方案,因此避免了一段时间。但是我们也可以对主表进行更新,事先将受影响的行的状态保存在某些缓存中。

可以将其与两层结合(由Zathrus提出的交通警察系统),因为neonski的使用"草图板"表的解决方案实际上并不需要它。这样做的缺点是我们必须让procs / logic从工作区中查询主表或者从主表中的工作区中查询-或者将标志存储在主表中,并在将数据提交给主表。

我们团队中的一位女士正在使用永久工作表为实时系统设计类似的东西。

一些建议:

  • 使用补偿交易。基本上,我们可以撤消之前所做的事务。困难的部分是弄清楚要回滚哪些事务。
  • 使用一个标志将应用程序A和B的数据提交到数据库,这仅是临时的。然后,在一切正常检查之后,修改标志以指示数据是最终的。在夜间,运行批处理作业以清除尚未完成的数据。