【发布时间】:2017-04-06 14:13:51
【问题描述】:
我开发了一个在线预订系统。为简化起见,假设用户可以预订多个项目,并且每个项目只能预订一次。商品首先添加到购物车中。
应用使用MySql / InnoDB 数据库。根据 MySql 文档,默认隔离级别为Repeatable reads。
这是我目前想出的结帐程序:
- 开始交易
- 选择购物车中的商品(带有
for update锁定)
在这一步从cart-item和items表中获取记录。- 检查物品是否未被其他人预订
基本上检查是否quantity > 0。在实际应用中比较复杂,所以我把它作为一个单独的步骤放在这里。- 更新项目,设置
quantity = 0
还可以执行其他必要的数据库操作。- 付款(通过 PayPal 或 Stripe 等外部 API)
无需用户交互,因为可以在结帐前收集付款详细信息。- 如果一切正常提交事务或回滚否则
- 继续不重要的逻辑
成功时发送电子邮件等,错误时重定向。
我不确定这是否足够。我担心是否:
- 尝试同时预订相同项目的其他用户将得到正确处理。他的交易
T2会等到T1完成吗? - 使用 PayPal 或 Stripe 付款可能需要一些时间。这不会成为性能方面的问题吗?
- 项目可用性将始终正确显示(项目应该可用,直到结帐成功)。这些只读选择是否应该使用
shared lock? - MySql 有可能自己回滚事务吗?通常是自动重试还是显示错误消息让用户再试一次更好?
- 我想如果我在
items表上执行SELECT ... FOR UPDATE就足够了。这样,由双击引起的请求和其他用户都必须等到事务完成。他们会等待,因为他们也使用FOR UPDATE。与此同时,vanillaSELECT只会在事务之前看到 db 的快照,但不会有任何延迟,对吧? - 如果我在
SELECT ... FOR UPDATE中使用JOIN,两个表中的记录会被锁定吗? - 我对Willem Renzema 回答的SELECT ... FOR UPDATE on non-existent rows 部分有点困惑。什么时候会变得重要?你能举个例子吗?
以下是我读过的一些资源: 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 我只选择通过
cart-item数据透视表已经存在的行
标签: mysql database concurrency transactions locking