Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel lockforupdate (Pessimistic Locking)

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

like image 455
user259752 Avatar asked Jan 01 '16 13:01

user259752


People also ask

What is pessimistic locking in Laravel?

The pessimistic locking is easy to implement using DB transaction as below. In Laravel, all the DB operations between beginTransaction and commit are guaranteed to be committed atomically. Pessimistic Transaction. And, the optimistic locking is, further, implemented as below.

What is lockForUpdate in Laravel?

A “for update” lock prevents the selected records from being modified or from being selected with another shared lock. This is what we want. If we run lockForUpdate in our find() statements, they will not be selected by another shared lock.

What is pessimistic locking?

Pessimistic lockingAs soon as one user starts to update a record, a lock is placed on it. Other users who attempt to update this record are informed that another user has an update in progress. The other users must wait until the first user has finished committing their changes, thereby releasing the record lock.

What is Sharedlock Laravel?

From Laravel documentation: A shared lock prevents the selected rows from being modified until your transaction is committed. So as it is written - lock will be active from when you call it until your transaction is done.


2 Answers

This work, finally, but still don't understand what sharedLock(LOCK IN SHARE MODE) and lockForUpdate(FOR UPDATE) different

    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;
        }));
    }
like image 99
user259752 Avatar answered Oct 06 '22 09:10

user259752


So this is old question but I believe my answer can clarify how ->lockForUpdate() works

From Laravel documentation:

A shared lock prevents the selected rows from being modified until your transaction is committed.

So as it is written - lock will be active from when you call it until your transaction is done.

Remember:

->find(1) works like ->first(), ->get(), ->insert(), ->save() etc. - it executes the query

->lockForUpdate() works like ->where(), ->select(), join() etc. - it adds to the query, but doesn't execute it

$model = \App\Models\User::find(1)->lockForUpdate(); - you try to add lock after query has already executed

$model = \App\Models\User::lockForUpdate()->find(1); - you add lock before query is executed therefore lock is active until transaction is finished

Difference is that in 1st scenario ->lockForUpdate() wasn't executed when you taught that it was

like image 32
NoOorZ24 Avatar answered Oct 06 '22 08:10

NoOorZ24