多个数据库事务

徘徊边缘 提交于 2019-12-06 04:41:14

在我的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();
          }
     }
}

但不确定是否

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

你怎么看?

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

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


#1楼

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

也许实际上并没有要求一个好的解决方案。 您是否面临困难的性能限制? 一般来说,交易时间应该很短......但也许您应该围绕网络服务电话保持交易开放? 这会降低数据库的整体吞吐量(至少)......但这可能是完全可以接受的。

您展示的方法在处理硬系统故障(电源故障,硬件故障等)时会遇到问题。 要解决此问题,您需要将跟踪添加到主数据库以及后台进程/启动过程以处理故障。 非常繁琐,但肯定可能。

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

祝好运。


#2楼

保持数据库同步是一项艰巨的任务,取决于您拥有的数据,您是否可以添加包含已更改内容的另一个表,然后通过cron或单独的代码运行单独的脚本,以尝试更新Web服务并使其与之同步存储在数据库中的更改。 如果更改成功,则会删除指定尚未将更改发送到远程服务器的标志。

在插入数据后的本地数据库上,您可以使用一个标志来指定它不应该生效,然后同步的任何和所有数据都会将该标志更改为完全提交。

这样做的具体原因是什么? 为什么需要在应用程序本身中保持两个数据库同步,您是否能够每小时同步一次?

这将需要状态跟踪数据以及它是否已成功提交到两端。

我个人的选择是数字1.回滚本地交易,除非绝对不可能使用数字2。


#3楼

我不明白,你的应用程序是PHP还是C#? 如果它在C#(WCF)中并且Web服务是WCF(或支持WS-AtomicTransaction),那么这是可能的。


#4楼

最大的问题是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;

然后,您需要一个常规任务,线程或其他类似的东西:

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

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

基本失败:

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

  2. 第一次提交后但在Web服务完成之前失败(这包括Web服务本身的瞬时故障):恢复任务重放远程Web服务事务。

  3. Web服务完成后但在第二次提交完成之前失败:恢复任务检测到重复的Web服务事务,并且本地记录已出列。

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

其他说明:

  • 渐进式退避方法对故障很有用。 如果服务出现暂时故障,您希望减慢重试速度。

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

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

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

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

当一个或两个系统发生故障时,您需要一些东西来拾取碎片并协调一些事情。 您可以使用完全成熟的TP监视器来进行事务协调,或者您可以构建一个简单的监视器,就像我的示例中处理您的特定情况的监视器一样。 无论哪种方式,都有一些东西可以跟踪发生的事情,以便在发生故障后能够正确解决问题。

如果您的要求确实是事情总是一起发生(并且事务性消息队列或两阶段提交方法对您不起作用),那么最好将两个系统的数据存储在同一个数据库中(也就是“资源管理器”)并且具有单个资源管理器事务。

如果你确实得到了这个问题的解决方案,它满足了在多个事务中使两个独立系统保持一致的要求,并且在发生故障后从不需要后续协调,那么你应该将其编写并在VLDB Journal,ACM TODS或IEEE TKDE中发布。 。


#5楼

我不认为回滚真的会有助于这种情况。 如果您的网络服务中断,拨打更多电话只会使问题复杂化,然后您必须担心您的回滚是否通过等等。

我会通过预定的完全同步来完成此操作。 你的错误保证金是多少? 您是否愿意让数据库略微不同步? 多少钱? 每晚都要运行一个同步器以解决任何问题,这是一件大事吗? Web服务的频率是多少,您必须担心这个问题?

失败的Web服务调用的更新队列是一个不错的主意,但是如果您的Web服务出现故障,那么可能会同时出现大量的内容,而不仅仅是一两个,因此您可能会在完成同步之后执行完全同步。无论如何停电。

你的答案真的取决于那些问题。 如果事情在10分钟内不同步0.01%,那么不要误以为假设整个程序都会崩溃。 找出错误的可接受余量。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!