场景是这个
我们有两个应用程序A和B,它们都在单独的数据库(Oracle 9i)事务中运行
应用程序A - 将一些数据插入数据库,然后调用应用程序B. 应用程序B - 将一些数据插入数据库,与A的数据相关(通过外键)。返回应用程序A的“ID” 应用程序A - 使用ID插入更多数据,包括来自B的ID
现在,因为这些是单独的事务,但两者都依赖于来自其他事务的数据,我们需要在每个应用程序的调用之间进行提交。这当然使得如果出现任何问题就很难回滚。
如何通过最少的代码重构来解决这个问题。当然,这种情况在SOA世界中是一个常见问题吗?
------更新--------
我无法在Oracle 9i中找到任何内容,但是Oracle 11g提供了DBMS_XA,这正是我所追求的。
答案 0 :(得分:11)
您有三种选择:
重新设计应用程序,以便您没有两个不同的进程(都有数据库连接)写入数据库并将其滚动到一个应用程序中。
创建处理A和B的所有数据库事务的应用程序C.
滚动您自己的两阶段提交。应用程序C充当协调者。 C发信号A和B询问他们是否准备好提交。 A和B进行处理,并使用“就绪”或“失败”回复来响应C(请注意,如果一个进程挂起或死亡,C上应该有超时以避免无限等待)。如果两个回复都准备就绪,那么C告诉他们提交。否则它会发送回滚信号。
请注意,如果应用A依赖于来自应用B的外键(您没有说明,那么这可能不是问题),您可能会遇到选项3的问题。 Oracle的读取一致性可能会阻止这种情况被允许,因为应用A的事务将在应用B之前开始。只是一个警告。
答案 1 :(得分:3)
一些建议:
使用Compensating transactions。基本上,您可以撤消先前执行的事务。困难的部分是确定要回滚的交易。
使用指示它只是临时的标志将应用程序A和B的数据提交到数据库。然后,在所有检查完成之后,修改标志以指示数据是最终的。在夜间,运行批处理作业以清除尚未最终确定的数据。
答案 2 :(得分:2)
您可以将应用程序A中的数据插入“临时”区域,这样应用程序B就可以插入A和B,而不会在任何应用程序中进行太多更改。它并不是特别优雅,但它可能会成功。
在另一种情况下,您可以在数据中添加“确认”标志字段,该字段在整个过程成功运行后更新。如果在某一点失败,可能更容易追踪您需要回滚的记录(实际上,删除)。
答案 3 :(得分:1)
我喜欢这两个解决方案,所以我避免发布一段时间。但您也可以对主表进行更新,事先保存了某些缓存中受影响行的状态。
这可以与双层(交通警察系统Zathrus提出)结合使用 - 因为neonski使用“画板”表或桌子的解决方案确实不需要它。这样做的缺点是你必须让你的procs / logic从工作区或主表的工作区查询主表 - 或者可能将你的标志存储在主表中,并在你提交数据时将其设置回来主表。
我们团队中的一位女士正在使用永久性工作表为我们的实时系统设计类似的东西。
答案 4 :(得分:0)
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之前不做任何事情。这意味着将它们放在不同的应用程序中,甚至是单独的线程都没有意义。