Yat*_*ath 6 java database concurrency transactions e-commerce
我一直在尝试了解亚马逊将如何处理并发写入问题,例如当多个用户尝试购买可用数量只有一件的同一产品时。
考虑到“产品”表具有以下字段:
我正在寻找有关数据库事务和锁定的详细解释,或者以更详细的技术术语处理这种情况的任何其他方法。
假设当 2 位用户在购物车中添加了相同的产品并且一位用户继续付款时:
A)
开始交易
从产品中选择 *,其中 ID = 1 且状态 =“可用”进行更新;
将产品表中的数量字段更新为“0”且状态 =“已售完”
调用支付网关
如果付款超时 回滚
犯罪
结束交易
=================================================== ========================= 当上述事务仍在进行时,其他用户仍然可以看到可用的产品,因为它仍未提交,他们可能会也继续付款。
此外,如果有足够数量的产品可用,锁定产品行可能会阻止其他用户同时尝试购买相同的产品。
=================================================== =========================
如何处理这个问题?
我已阅读以下关于在数据库上使用乐观锁定的博客,但发现很难深入理解到底如何实现。
让两个事务同时运行上述代码,分别命名为tx1和tx2。tx1 和 tx2 都会首先尝试运行
SELECT * FROM PRODUCT WHERE ID = 1 AND STATUS = "AVAILABLE" FOR UPDATE;
Run Code Online (Sandbox Code Playgroud)
该查询还意味着从结果集中获取该行的锁。当然,只有一笔交易可以获取它,因此另一笔交易将不得不等待。例如,如果 tx1 获取了锁,则 tx2 将等待,直到 tx1 提交并释放锁。然后,tx2 也会继续并提交,因为它只是将数量设置为 0。因此,上述方法将无法按预期工作,因为最终,两个用户都会收到有关其购买的成功消息。如果您想保留这种方法,不是直接将数量设置为零,而是将其减少 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 的情况,乐观锁定仍会导致一个事务中止,而使用悲观锁定可以成功服务这两个事务,但会稍微牺牲性能。
当上述事务仍在进行时,其他用户仍然可以看到可用的产品,因为它尚未提交,并且他们也可以继续付款。
对此,可能与用户屏幕的刷新率有关。即使用户能够继续付款(前端数据过时),后端也应验证用户是否有资格进行购买,如果是,则继续购买(所有这些都在一次交易中完成) )
此外,如果有足够数量的产品可用,锁定产品行可能会阻止其他用户同时尝试购买相同的产品。
这就是悲观锁的要点,性能下降是其主要影响,但只要数量不达到0,所有事务都可以服务。乐观锁中,只有1会成功,其他都会失败,提示用户尝试再次购买。