【发布时间】:2018-03-27 14:15:21
【问题描述】:
所以我试图弄清楚如何避免竞争条件。 我有一个产品,您可以在其中预订有限的资源。
每个资源都有一定数量的容量。容量是根据名为 booking_resources 的数据库表中的行数来计算的,其中每个预订的资源都有一行。
在代码执行期间,我会进行多项检查,例如:
- 此人是否有权访问
- 资源在给定时间范围内是否可用
- 预订选项是否有效
- 进行预订
“进行预订”时,预订所需的资源被插入到 booking_resources 表中。这使得具有 resource_id 的行数增加,从而使下一次检查资源在给定时间范围内可用。 我的问题是我找不到任何关于在这种情况下该怎么做的文档。 我应该在我的资源表中添加一个额外的列并以这种方式锁定该行吗? (我使用 innodb)
我读过一些关于使用 select ... for update.. 的内容,但这在我的情况下没有意义,因为我没有“缓存”该行中的预订数量。 整个想法是我有一个 24/7 可用的资源,每次预订都会占用它的一些容量。它的容量可能为 10(这意味着我可以让 10 个人同时使用该资源)。这也意味着(理论上)人们对资源的预订可以重叠,只要不超过 10 人同时使用它。
希望我的问题能说明我面临的问题,并希望你们有一个优雅的解决方案来防止我的应用程序超额预订。
数据结构:
预订:
标识 | company_id |积分 |来自 |到 |价格 |预订数据 |预订者选择 | due_order_id_datetime(如果不是订单的一部分,则删除预订时)|创建 |更新 |已删除
booking_resources:
标识 |预订ID |资源 ID |来自 |到 |积分 |创建 |更新 |已删除
资源:
标识 | company_id |姓名 | min_booking |最大预订量 | min_points |最大点数 |创建 |更新 |已删除
为了能够重现该问题,我制作了一个 javascript,可在两个不同的窗口中同时单击同一个按钮。这是通过使用 settimeout 计时器和点击事件(使用 jquery)来完成的。
<script>
function syncClick(selector,time_to_activate){
date = new Date();
if(date.getTime() >= time_to_activate){
console.log('clicked');
jQuery(selector).click();
} else {
setTimeout(function(){
console.log("diff:"+(date.getTime() - time_to_activate));
syncClick(selector,time_to_activate);
},1);
}
}
</script>
谢谢。 /W
【问题讨论】:
-
你在使用事务吗?
-
嗯......不......但这只是因为我看不到交易在这里会有什么帮助。他们真的锁定了桌子本身吗?所以一次只能插入一件东西?我是否必须进行插入,然后“检查”它是否仍然存在,如果没有,则将其中一项事务“回滚”?
-
好吧,如果您将多个数据库添加/更新/删除操作作为一个序列的一部分,那么建议您在语句失败或无法执行时防止数据不一致(例如,因为它未通过测试,例如可用的东西)。目前尚不清楚这是否是您的场景的一部分,但听起来可能是这样。它可能不是您问题的解决方案,但它应该在其他方面有所帮助。
-
无论如何,你还没有真正给我们一个真正清晰的情况。我们看不到您的实际数据结构或您如何计算容量。但理想情况下,如果有人询问特定时间段,您或许应该暂时将其锁定,直到他们确认。并给他们一个时间限制,直到他们的独家访问结束。很多票务网站都会为热门活动这样做——您选择多张票,然后您有几分钟时间确认预订并付款,然后再重新向公众发布,您可能会丢失它。跨度>
-
我会在一秒钟内评论你写的所有东西。只是为了给一个清晰的图像。 “this”实际上是时间范围的锁定。创建预订后,您有 X 分钟的时间确认(创建订单 - 并付款)..
标签: php mysql race-condition