我正在创建一个与MySQL清单数据库交互的API。我们有15个用户可以预订产品,通过以下方式更新数据库:
降低产品的on-hand
值并增加reserved
值。inventory
表如下所示:
id int
sku varchar
on-hand int
reserved int
问题是:如果两个用户同时尝试更新行,如何处理该行的更新?
我想的第一个方法是使用Transactions:
<?php
function reserveStock()
{
$db->beginTransaction();
// SELECT on-hand, reserved from inventory
// Update inventory values
$db->commit();
return response()->json([ 'success' => 1, 'data' => $data ])
}
第二种是使用pessimist locking:
<?php
function reserveStock()
{
// SELECT on-hand, reserved from inventory with ->sharedLock()
// Update inventory values
return response()->json([ 'success' => 1, 'data' => $data ])
}
第三个是创建一个值为cero的
updating
字段。在选择要更新的产品时,我会在对该行执行任何操作之前检查updating
字段。我在这里看到的问题是,我必须循环使用updating != 0
的选项,直到它们可用为止。更多的选择和更新来自他的提议。哪种方法最好?可能有比我在这里写的更多的选择。
最佳答案
不要使用两个事务都不使用悲观锁定。
也不要使用update。
对于赛车状态的情况,您最好检查您的数据库,并摆脱更新,而使用插入。制作一个数据透视表以适应用户和产品之间的连接。并且只将第一个连接记录(其中id较小)设为实际记录。
如果需要更多的解释,这里有一个例子:
假设有两个用户竞相购买产品。它们都在透视表中创建记录,几乎同时创建,但应该有人是firs,对吧?它们都提交非常小的事务来保存数据。然后-他们都读取透视表来验证谁成功了。第一条记录对它们都是一样的,在使用中没有阻塞(至少是显式的)。所以一个客户会得到他的记录,并感到高兴,另一个将重新申请获得另一个产品。
问题解决了。