大多数文章都讨论 2 Phase commit 或 Saga 模式,但没有
详细说明一个对象是如何被锁定的,这样其他人就无法访问
交易未完成时的数据。
2PC 被定义为阻塞。这意味着,如果管理 2PC 事务的事务管理器出现故障,则 2PC 将无法解决。事务管理器是单点故障。
如果确保重新启动失败的事务管理器,那么即使 2PC 协议被认为是阻塞的,您也可以确保事务管理器可用并且解决方案不会被阻塞。
然后 2PC 使用锁。它们是协议的基本元素。事务管理器与参与者 - 资源进行通信。参与者是数据库。当 2PC 开始运行时,调用 prepare 意味着数据库对参与事务的所有行进行持久锁定。这个锁在事务管理器调用提交时被释放。
重要的是要了解 2PC 之前的事务是在进行中(不是持久的)。它存储在内存中。在调用准备之后,事务状态被持久存储,直到调用提交(那时协议可能被不可用的事务管理器阻塞 - 锁是持久的,系统等待事务管理器释放它)。
从 2PC 的角度来看,这是关于锁定的。但是从数据库的角度来看,有事务锁。
当您更新数据库中的一行时,事务就在进行中(存储在内存中)。那时数据库需要确保并发更新不会破坏您的数据。一种方法是锁定行并且不允许并发更新。
但是,大多数数据库不会锁定行 - 默认情况下,取决于隔离级别 - 在这些情况下,因为它们使用快照隔离(MVCC,https://en.wikipedia.org/wiki/Snapshot_isolation)。这尤其意味着该行被乐观锁定,并且数据库允许其他事务更新该行。
但是! 2PC prepare 不能乐观处理。当数据库回复“OK”以准备来自事务管理器的请求时,该行就被锁定了。
另外,您无法手动管理此锁定。如果你试图这样做,你会破坏 2PC 的一致性保证。
在您的示例中,有客户服务和订单服务。当 2PC 事务跨越这两个服务时。然后客户更新数据库,订单服务也更新数据库。数据库中仍在运行中的事务。然后请求完成并且事务管理器命令进行中的事务提交。它运行2PC。它在客户服务数据库事务上调用准备,然后在订单服务事务上调用提交。
如果您使用 saga 模式,那么 saga 会跨越这两个服务。从事务的角度来看,客户服务会创建一个数据库中的事务并立即提交它。然后呼叫转到订单服务,同样的事情也会发生。当请求完成时,saga 会检查一切是否正常。当发生故障时,将调用补偿回调。
从易用性的角度来看,故障是“麻烦”。对于 saga,您需要在回调方法中自行维护故障解决方案。对于 2PC,故障解决由回滚调用自动处理。
注:我试图在这里总结2PC:https://developer.jboss.org/wiki/TwoPhaseCommit2PC
我不确定解释是否足够理解,但您可以尝试检查。你可以让我知道那里的错误解释。谢谢。