多个数据库事务

Gra*_*ton 6 database-design symfony1

在我的PHP应用程序(使用symfony框架和Propel ORM构建)中,当我向MYSQL数据库添加记录时,我需要使用外部供应商提供的Web服务API更新外部MYSQL数据库.

问题是维护数据库完整性的最佳实践是什么.举例来说,如果第一次更新成功,而第二次更新不成功,由于Web服务不可用,我必须能够

  1. 回滚第一次更新的事务,或
  2. 缓存对Web服务的调用,并继续调用Web服务,直到服务可用
  3. 一些其他可以保持多个数据库完整性的技术.

具体来说,我正在寻找类似的语法

void RootMethod()
{
     using(TransactionScope scope = new TransactionScope())
     {
        try
         { 
          SomeMethod();
          scope.Complete();
          CallWebService();
         }
         catch
         {
             scope.abort();
          }
     }
}
Run Code Online (Sandbox Code Playgroud)

但不确定是否

  1. 这是一个很好的技术
  2. 或者这在symfony中是可行的,就像在C#中一样

你怎么看?

编辑:有些人问我为什么需要两部分更新.这是因为我正在创建一个连接到现有后端应用程序的前端应用程序.我不想改变后端应用程序.因此不可避免地会有一些重叠.因此需要同步数据

另一个编辑:两部分事务必须一起完成,做一个cron作业同步表是不可取的

use*_*794 5

这会很棘手。您需要两阶段提交才能获得可靠的解决方案,但这将需要大量工作才能满足您的特定需求。

也许实际上并不需要一个好的解决方案。您是否面临困难的绩效限制?一般来说,交易的时间应该很短......但也许您应该在 Web 服务调用周围保持交易开放?这会降低数据库的整体吞吐量(至少)......但这可能是完全可以接受的。

您展示的方法在处理硬系统故障(电源故障、硬件故障等)时会遇到问题。要解决这个问题,您需要向主数据库添加跟踪和后台进程/启动进程来处理故障。做起来相当繁琐,但肯定是可能的。

某些故障可能最终无法修复(第一部分成功,第二部分失败,第一部分无法撤消,因为另一个事务已更新相同的数据)。这一切都取决于您精确的业务规则。会计系统将是最简单的,因为撤消交易实际上是作为抵消记录而不是更新来完成的。

祝你好运。

  • 在进行 Web 服务调用时保持事务打开仍然会导致窗口状态不一致。有一个窗口,本地事务回滚,但 Web 服务事务完成。 (2认同)

jan*_*anm 5

最大的问题是对Web服务的重复更新是否重要,以及是否可以检测到。如果可以检测到重复项(通常具有唯一的事务编号),或者如果重复项无关紧要,则可以构建一种可靠的两阶段提交样式方法。

如果无法检测到与Web服务的重复交易,并且更新不是幂等的,那么您很不走运。

这是基本算法:

begin transaction;
do local work;
save information for external call;
set an appropriate time for next attempt;
mark external call as not performed;
commit work;

begin transaction;
make external call;
if successful
   mark external call as performed (or delete the record)
else
   set the time for the next attempt
commit;
Run Code Online (Sandbox Code Playgroud)

然后,您需要一个常规任务,线程或执行以下操作的任何东西:

for each record where the time for the next attempt <= now
    begin work;
    if the remote service has not performed this transaction
        make the remote call;
        if successful
            mark as done;
        else if too many attempts
            mark the transaction as permanently failed;
            alert operator;
        else
            set the time for the next attempt;
        endif
    else
        mark as done;
    endif

    commit;
 endfor
Run Code Online (Sandbox Code Playgroud)

这种方法可以可靠地处理所有故障情况,并确保最终完成两项工作。

基本故障:

  1. 在第一次提交完成之前失败:一切都回滚。

  2. 在第一次提交之后但在Web服务完成之前发生故障(这包括Web服务本身中的短暂故障):远程Web服务事务由恢复任务重播。

  3. Web服务完成之后但第二次提交完成之前发生故障:恢复任务检测到重复的Web服务事务,并且使本地记录出队。

  4. 恢复任务中的失败:与第二个事务中的失败基本相同。

其他说明:

  • 渐进的退避方法对于失败很有用。如果服务暂时出现故障,则需要减慢重试的时间。

  • 如果您对外部服务有订购要求,则可能需要一些其他结构。

  • 根据执行恢复任务的方式,您可以仅将Web服务调用留给该任务,而在主应用程序流中不包含第二个事务。

对附加要求的响应:“两个部分的事务必须一起完成,不希望执行cron作业来同步表”

我对这一要求的理解是:“这两个系统永远都不会失败。”

当一个或两个系统发生故障时,您需要采取一些措施来解决问题并进行协调。您可以使用成熟的TP监视器来进行事务协调,也可以构建一个简单的监视器,例如本例中处理特定情况的监视器。无论哪种方式,都可以跟踪发生的事情,以便在出现故障后可以正确解决问题。

如果您的需求确实是总是在一起发生(并且事务性消息队列或两阶段提交方法不适合您),那么最好将两个系统的数据存储在同一数据库中(也称为“资源管理器”) )并进行一次资源管理器交易。

如果您确实找到了一个解决方案,该解决方案满足了使两个独立的系统在多个事务中保持一致并且在故障发生后不再需要对帐的要求,则应将其记录下来并发布在《 VLDB Journal》,《 ACM TODS》或《 IEEE TKDE》中。