并发请求中的Laravel数据库锁定表

时间:2018-07-24 14:57:34

标签: php database laravel table-lock

如果突然有多个请求发送到我的数据库并同时更新,我想阻止我的数据库更新。

我创建一个用户Laravel Users Table作为示例,并使用JMeter模拟有两个用户,发送并发请求以更改同一行数据。

例如场景

我的银行帐户有$ 1000。同时,有两个请求从我的帐户向A和B先生转账。

我的余额记录为1000,请求1-向A先生发送$ 700,请求2-向B先生发送$ 700。如果我没有锁好桌子,系统将被视为我有足够的余额将钱寄出。

我的目标是当涉及到并发请求时,第二个(FIFO,即使是并发Web服务器仍然会对其进行处理,并将其中一个视为第二个)将引发异常/或显示返回错误要求说它正在使用中。

下面是我的测试代码,我使用JMeter运行测试。但是,测试显示两个请求都已更新。因此,最新请求将覆盖第一个请求。

以下,我希望Laravel会为数据库锁定抛出异常或错误,但仍会继续。

Route::get('/db-a', function() {

    \DB::beginTransaction();

    //lock the table
    $rs = \DB::table('users')->where('id', '1')->lockForUpdate()->first();

    $sql = "update users set remember_token='this is a' where id=1";
    \DB::update(DB::raw($sql));

    //purposely put the sleep to see can the table / row be locked

    sleep(3);

    \DB::commit();

    $rs = DB::table('users')->where('id', '1')->first();
    echo($rs->remember_token);
    return;
});

Route::get('/db-b', function () {

    \DB::beginTransaction();

    //lock the table
    $rs = \DB::table('users')->where('id', '1')->lockForUpdate()->first();

    $sql = "update users set remember_token='this is b' where id=1";
    \DB::update(DB::raw($sql));

    //purposely put the sleep to see can the table / row be locked
    sleep(3);


    \DB::commit();

    $rs = DB::table('users')->where('id', '1')->first();
    echo($rs->remember_token);
    return;
});

我做了另一个版本来手动捕获异常,但也无法正常工作

Route::get('db-callback-a', function() {
    try {
        app('db')->transaction(function () {
            $record = \DB::table('users')->where('id', 1)->lockForUpdate()->first();
            $sql = "update users set remember_token='this is callback a' where id=1";

            \DB::update(DB::raw($sql));
            sleep(3);
        });
    } 
    catch (\Exception $e) {
        // display an error to user
        echo('Database Row in Use, update later');
    }
});

Route::get('db-callback-b', function () {
    try {

        app('db')->transaction(function () {
            $record = \DB::table('users')->where('id', 1)->lockForUpdate()->first();
            $sql = "update users set remember_token='this is callback b' where id=1";


            \DB::update(DB::raw($sql));
            sleep(3);
        });
    } catch (\Exception $e) {
        // display an error to user
        echo ('Database Row in Use, update later');
    }
});

0 个答案:

没有答案