Таблица блокировки базы данных Laravel в параллельном запросе

Я хочу запретить обновлять мою базу данных, если внезапно несколько запросов отправляются в мою базу данных и обновляются одновременно.

Я создаю пользовательскую таблицу пользователей Laravel в качестве примера и использую JMeter для симуляции двух пользователей, отправляющих параллельный запрос на изменение одной и той же строки данных.

Например, сценарий

Мой банковский счет имеет 1000 долларов. В то же время, два запроса на перевод денег мистеру А и мистеру Б. отправляются с моего счета.

Мой счет для баланса - 1000, Запрос 1 - Отправьте 700 долларов мистеру А, а Запрос 2 - Отправьте 700 долларов мистеру Б. Если я не заблокировал стол, система будет обработана. У меня достаточно средств для отправки денег.

Моя цель состоит в том, что когда дело доходит до одновременного запроса, второй (FIFO, даже если веб-сервер параллелизма по-прежнему будет обрабатывать его и обрабатывать один из них как второй), выдаст исключение / или покажет ошибку возврата для запроса, который он использует,

ниже приведен мой код для теста, и я использую 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 ответов

Другие вопросы по тегам