douyun8885 2018-07-24 14:57
浏览 162

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

I want to prevent my database to update if suddenly multiple requests send to my database and updated at the same times.

I create user Laravel Users Table as an example and use JMeter to simulate there are two users, sending concurrent request to change the same row of data.

E.g Scenario

My bank account has $1000. In the same times, two requests send in for transfer money to Mr. A and Mr.B from my account.

My record for balance is 1000, Request 1 - Send $700 to Mr.A, and Request 2 - Send $700 to Mr.B. If I didn't lock the table, the system will be treated I have enough balance to send out the money.

My goal is when it comes to concurrent request, the 2nd (FIFO, even it is concurrency web server still will process it and treat one of it as second) will throw the exception / or show return error to the request said it is in use.

below is my code for a test, and I use JMeter to run the test. However, the test shows that both requests are updated. Hence, the latest request will overwrite the first request.

Below, I am expecting Laravel will throw exception or error for database lock, but it still proceed.

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;
});

I do another version for manually catch the exception, but also not working

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条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
    • ¥100 为什么这个恒流源电路不能恒流?
    • ¥15 有偿求跨组件数据流路径图
    • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
    • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
    • ¥15 CSAPPattacklab
    • ¥15 一直显示正在等待HID—ISP
    • ¥15 Python turtle 画图
    • ¥15 stm32开发clion时遇到的编译问题
    • ¥15 lna设计 源简并电感型共源放大器