我开发了一个在线预订系统。为了简化,我们假设用户可以预订多个项目,并且每个项目只能预订一次。项目首先添加到购物车。如何正确使用事务和锁确保数据库的完整性?
应用程序使用MySql
/InnoDB
数据库。根据MySql文档,默认隔离级别为Repeatable reads
。
这里是我和到目前为止想出了检验过程:
- BEGIN TRANSACTION
- 选择项目在购物车(与
for update
锁)从
记录cart-item
和items
在这一步取得表格。- 检查是否有物品未被其他人预订
基本检查是否quantity > 0
。在实际应用中它更复杂,因此我把它作为一个单独的步骤放在这里。- 更新项目,设置
quantity = 0
也执行其他基本数据库操作。- 付款(通过外部API如贝宝或条纹)
没有用户互动是必要的,因为付款的细节可以在结帐前收集。- 如果一切正常提交事务或回滚否则
- 与非基本逻辑继续
发送电子邮件等,在成功的情况下,重定向错误。
我不确定这是否足够。我担心是否:
- 其他试图同时预订同一项目的用户将被正确处理。他的交易
T2
会等到T1
完成吗? - 使用PayPal或Stripe付款可能需要一些时间。这不会成为性能方面的问题吗?
- 项目可用性将始终显示正确(项目应可用,直到结帐成功)。如果这些只读选择使用
shared lock
? - MySql有可能自行回滚事务吗?自动重试或显示错误消息并让用户再试一次通常会更好吗?
- 我想它足够了,如果我在
items
表上做SELECT ... FOR UPDATE
。这样,双击和其他用户引起的请求都必须等到事务结束。他们会等待,因为他们也使用FOR UPDATE
。同时香草SELECT
只会在交易前看到数据库的快照,尽管如此,对吧? - 如果我在
SELECT ... FOR UPDATE
中使用JOIN
,两个表中的记录是否都会被锁定? - 我有点困惑选择...更新不存在的行部分威廉雷泽马答案。什么时候变得重要?你能提供任何例子吗?
这里有一些资源,我读过: How to deal with concurrent updates in databases?,MySQL: Transactions vs Locking Tables,Do database transactions prevent race conditions?, Isolation (database systems),InnoDB Locking and Transaction Model,A beginner’s guide to database locking and the lost update phenomena。
重写了我原来的问题,使之更加普遍。
增加后续问题。
重要的问题:当你'SELECT ... FOR UPDATE',你选择对您知道已经存在,或者针对您打算插入行的行? –
@WillemRenzema我只选择已通过'车,item'透视表 – Paul