17

i'm trying to figure out how to use/test the lockforupdate correctly, but i found is not function like what i expected

this is just testing

public function index() {
        return dd(\DB::transaction(function() {
            if (\Auth::guard('user')->check()) {
                $model = \App\Models\User::find(1)->lockForUpdate();
                sleep(60);
                $model->point = 100000;
                $model->save();
            } else {
                $model = \App\Models\User::find(1);
                $model->point = 999;
                $model->save();
            }

            return $model;
        }));
}

i try to test in 2 browser, browser 1 user logged in and browser 2 not logged in, browser 1 hit refresh, then there will lockforupdate and sleep 60 seconds before update

in the 60 seconds, i go browser 2 and hit refresh, however the record is not locked, i check phpmyadmin and the record is updated(within the 60 seconds lock trigger by browser 1)

but after 60 seconds, the record has been modified again by browser 1(Point 100000)

so am i misunderstanding the lockforupdate is use for?or i test it incorrectly?

what i expected is the row shouldn't be modified by browser 2 in the first 60 seconds(blank page with loading favicon or error throw?)

https://laravel.com/docs/5.2/queries#pessimistic-locking

and i did some research but still cannot understand what different between sharedLock(LOCK IN SHARE MODE) and lockForUpdate(FOR UPDATE)

btw i confirmed the database is innodb

4

3 回答 3

20

这项工作终于完成了,但仍然不明白 sharedLock(LOCK IN SHARE MODE) 和 lockForUpdate(FOR UPDATE) 有什么不同

    public function index() {
        return dd(\DB::transaction(function() {
            if (\Auth::guard('user')->check()) {
                $model = \App\Models\User::lockForUpdate()->find(1);
                sleep(30);
                $model->point = 100000;
                $model->save();
            } else {
                $model = \App\Models\User::lockForUpdate()->find(1);
                $model->point = $model->point + 1;
                $model->save();
            }

            return $model;
        }));
    }
于 2016-01-01T13:45:29.313 回答
11

所以这是一个老问题,但我相信我的回答可以阐明如何->lockForUpdate()工作

来自 Laravel 文档:

共享锁可防止在提交事务之前修改选定的行。

因此,正如它所写的那样 - 从您调用它到您的事务完成,锁将处于活动状态。

记住:

->find(1)->first(), ->get(),->insert()等一样工作->save()- 它执行查询

->lockForUpdate()->where(),->select()等一样工作join()- 它添加到查询中,但不执行它

$model = \App\Models\User::find(1)->lockForUpdate();- 您尝试在查询已经执行后添加锁

$model = \App\Models\User::lockForUpdate()->find(1);- 在执行查询之前添加锁,因此锁在事务完成之前一直处于活动状态

不同之处在于,在第一种情况下,当你教它时->lockForUpdate() 没有执行

于 2021-03-09T13:04:29.427 回答
2

阅读本文参考

Laravel 中的悲观与乐观锁定

  • 共享锁:

    DB::table('users')->where('votes', '>', 100)->sharedLock()->get();
    
  • 锁定更新:

    DB::table('users')->where('votes', '>', 100)->lockForUpdate()->get();
    

Laravel 文档

于 2020-09-09T12:24:10.080 回答