在我的PHP应用程序(使用symfony框架和Propel ORM构建)中,当我向MYSQL数据库添加记录时,我需要使用外部供应商提供的Web服务API更新外部MYSQL数据库。
问题是维护数据库完整性的最佳实践是什么。 举例来说,如果第一次更新成功,而第二次更新不成功,由于Web服务不可用,我必须能够
- 回滚第一次更新的事务,或
- 缓存对Web服务的调用,并继续调用Web服务,直到服务可用
- 一些其他可以保持多个数据库完整性的技术。
具体来说,我正在寻找类似的语法
void RootMethod()
{
using(TransactionScope scope = new TransactionScope())
{
try
{
SomeMethod();
scope.Complete();
CallWebService();
}
catch
{
scope.abort();
}
}
}
但不确定是否
- 这是一个很好的技术
- 或者这在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
这种方法可靠地处理所有故障条件,并确保最终完成两项工作。
基本失败:
第一次提交完成之前的失败:一切都回滚。
第一次提交后但在Web服务完成之前失败(这包括Web服务本身的瞬时故障):恢复任务重放远程Web服务事务。
Web服务完成后但在第二次提交完成之前失败:恢复任务检测到重复的Web服务事务,并且本地记录已出列。
恢复任务中的失败:基本上与第二个事务中的失败相同。
其他说明:
渐进式退避方法对故障很有用。 如果服务出现暂时故障,您希望减慢重试速度。
如果您对外部服务有订购要求,则可能需要一些额外的结构。
根据您实现恢复任务的方式,您可以将Web服务调用留给该任务,而不是在主应用程序流中使用第二个事务。
对附加要求的回应:“两部分事务必须一起完成,执行cron作业来同步表是不可取的”
我对这个要求的解读是:“这两个系统永远不会失败。”
当一个或两个系统发生故障时,您需要一些东西来拾取碎片并协调一些事情。 您可以使用完全成熟的TP监视器来进行事务协调,或者您可以构建一个简单的监视器,就像我的示例中处理您的特定情况的监视器一样。 无论哪种方式,都有一些东西可以跟踪发生的事情,以便在发生故障后能够正确解决问题。
如果您的要求确实是事情总是一起发生(并且事务性消息队列或两阶段提交方法对您不起作用),那么最好将两个系统的数据存储在同一个数据库中(也就是“资源管理器”)并且具有单个资源管理器事务。
如果你确实得到了这个问题的解决方案,它满足了在多个事务中使两个独立系统保持一致的要求,并且在发生故障后从不需要后续协调,那么你应该将其编写并在VLDB Journal,ACM TODS或IEEE TKDE中发布。 。
#5楼
我不认为回滚真的会有助于这种情况。 如果您的网络服务中断,拨打更多电话只会使问题复杂化,然后您必须担心您的回滚是否通过等等。
我会通过预定的完全同步来完成此操作。 你的错误保证金是多少? 您是否愿意让数据库略微不同步? 多少钱? 每晚都要运行一个同步器以解决任何问题,这是一件大事吗? Web服务的频率是多少,您必须担心这个问题?
失败的Web服务调用的更新队列是一个不错的主意,但是如果您的Web服务出现故障,那么可能会同时出现大量的内容,而不仅仅是一两个,因此您可能会在完成同步之后执行完全同步。无论如何停电。
你的答案真的取决于那些问题。 如果事情在10分钟内不同步0.01%,那么不要误以为假设整个程序都会崩溃。 找出错误的可接受余量。