如何检查条件是否正确,然后在比赛条件下插入一些东西

时间:2019-06-24 12:13:17

标签: php mysql laravel mariadb

我们有一个api函数,它使用选择查询来检查数据库中的条件,如果是真的,我们只想一次向数据库中插入一些东西,例如,插入完成的数据库。问题是,当我们多次调用此api函数并发竞争条件时,换句话说,假设我们两次调用此函数,第一个请求检查条件为true,然后第二个请求检查条件为true,因此将它们插入数据库。但是我们希望在检查条件时没有其他人可以再次检查它,直到我们插入为止。

我们使用php / Laravel并了解一些方法,例如使用insert into ... select或使用诸如replace into ...之类的东西。

$order = Order::find($orderId);
$logRefer = $order->user->logrefer;
if (!is_null($logRefer) && is_null($logRefer->user_turnover_id)) {
     $userTurnover = new UserTurnover();
     $userTurnover->user_id = $logRefer->referrer_id;
     $userTurnover->order_id = $order->id;
     $userTurnover->save();

     $logRefer->order_id = $order->id;
     $logRefer->user_turnover_id = $userTurnover->id;
     $logRefer->save();
}

如果找不到logrefer,请将其和相应的user-turnover设置一次。我们期望只看到一个与此订单相关的user-turnover,但是在同时运行多次之后,我们看到已插入多个user-turnover

2 个答案:

答案 0 :(得分:1)

当操作需要顺序执行时,我通常会利用事务处理,但是我认为在您的情况下,这有点复杂,因为如果函数正在运行,还需要有条件地评估条件。因此,我可以为您提供的想法是,在数据库上有一个用作信号量的变量(另一个表),该变量允许或不对表执行操作(由您设置或取消设置信号量的值所提供的条件) 。我认为,作为一名优秀的程序员,信号量在许多并发函数中很有用。

答案 1 :(得分:1)

即使代码中的某些机制可以防止重复,数据库也应该在预期唯一的列上具有唯一键。

将连接的查询包装到事务中,该事务将失败并在竞赛事件条件下回滚

try {
    DB::transaction(function() {
        $order = Order::find($orderId);
        ...
        $logRefer->save();
    });
} catch (\Illuminate\Database\QueryException $ex) {
    Log::error(“failed to write to database”);
}