我一直在尝试了解亚马逊如何处理并发写入问题,例如当多个用户尝试购买可用数量仅为一个的同一产品时。
考虑到“ PRODUCT ”表具有以下字段:
我正在寻找关于数据库事务和锁定的详细解释,或者是以其他更详细的技术术语来处理这种情况的其他方法。
假设有2位用户在购物车中添加了相同的产品,而1位用户继续付款:
一个)
开始交易
SELECT * FROM PRODUCT ID = 1 AND STATUS =“AVAILABLE”进行更新;
将产品表中的数量字段更新为“0”,并且STATUS =“SOLD OUT”
呼叫支付网关
如果付款超时
ROLLBACK
COMMIT
END TRANSACTION
================================================== ========================
尽管仍在进行上述交易,但其他用户仍可以看到PRODUCT,因为该产品尚未提交,他们也可以继续付款。
同样,如果有足够数量的产品可用,则锁定产品行可能会阻止其他用户尝试同时购买同一产品。
================================================== ========================
如何处理这个问题?
我阅读了以下博客,该博客对数据库使用乐观锁定,但发现很难深入了解如何精确实现。
Design eCommerce Website - Concurrency
最佳答案
让两个事务同时运行上述代码,分别命名为tx1和tx2。
tx1和tx2都将首先尝试运行
SELECT * FROM PRODUCT WHERE ID = 1 AND STATUS = "AVAILABLE" FOR UPDATE;
该查询还意味着从结果集中获取该行的锁定。自然,只有一项交易可以获取,因此另一项交易必须等待。例如,如果tx1获得了锁,则tx2将等待直到tx1提交并释放锁。然后,tx2也将继续并提交,因为它只是将数量设置为0。结果,上述方法将无法按需工作,因为最后,两个用户都会收到有关其购买的成功消息。但是,如果您想保留此方法,则不是直接将数量减少为1,而是将数量减少为1,并对列指出其值不能降至0以下的约束。以这种方式,tx2将失败由于违反约束(记住ACID的C-一致性)并回滚,因此第二个用户将收到一条消息,表明他/她的购买失败。
另外,如果您不想在此特定示例中实施额外的约束,而只是直接设置数量,则可以采用乐观锁定,该锁定使用透明的行版本控制,并且在性能方面也更便宜。因此,对于ID为1的产品(我们将其称为P),tx1会生成P的新版本(P1),而tx2同时会生成P的另一个新版本(P2)。当tx1和tx2中的任何一个尝试提交时,系统将注意到存在P的新未提交版本P1和P2,并且将仅批准其中一个。结果,可以选择P1作为接受的P的新版本,从而tx1成功并且购买成功,并且P2被拒绝,因此tx2中止并回滚,并且第二用户收到有关其购买的失败消息。还要注意,相反的情况也可能发生,即P2被接受而P1被拒绝。
最后,关于乐观和悲观锁定,请考虑以下几点:
就我个人而言,我会选择悲观锁定,但要修复上述事务,因为对于数量大于1的交易,乐观锁定仍会导致一个事务中止,而使用悲观主义可以成功地为这两个事务提供服务,但会降低性能。
在进行上述交易时,其他用户仍可以看到PRODUCT,因为该产品尚未提交,他们也可能
继续付款。
关于这一点,可能与用户屏幕的刷新率有关。即使用户能够继续付款(前端有陈旧的数据),后端也应验证用户是否有资格进行购买,如果是,则继续购买(所有这些都通过一次交易完成) )
同样,如果有足够数量的产品可用,则锁定产品行可能会阻止其他用户尝试同时购买同一产品。
这就是悲观锁的关键点,性能下降是此问题的主要影响,但是只要数量不达到0,就可以处理所有事务。在乐观锁中,只有1会成功,其他会失败,提示用户尝试再次购买。