From 554684861abe7fea83dbe7305315ae2dba9f44d1 Mon Sep 17 00:00:00 2001 From: Italo Date: Wed, 15 Jan 2025 02:28:39 -0300 Subject: [PATCH 1/2] Add pessimistic locking extended example --- queries.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/queries.md b/queries.md index 4704519e22a..ff746a9a845 100644 --- a/queries.md +++ b/queries.md @@ -1191,6 +1191,34 @@ Alternatively, you may use the `lockForUpdate` method. A "for update" lock preve ->lockForUpdate() ->get(); +It is recommended, but not obligatory, to wrap pessimistic locks inside a [transaction](/docs/{{version}}/database#database-transactions), especially when you require the data retrieved not to be altered on the database until the entire logic is executed. In case of failure, the locks will be freed and any changes will be rolled back. + + DB::transaction(function () { + $sender = DB::table('users') + ->lockForUpdate() + ->find(1); + + $receiver = DB::table('users') + ->lockForUpdate(); + ->find(2); + + if ($user->balance < 100) { + throw new RuntimeException('The sender has not enough balance'); + } + + DB::table('users') + ->where('id', $sender->id) + ->update([ + 'balance' => $sender->balance - 100 + ]); + + DB::table('users') + ->where('id', $receiver->id) + ->update([ + 'balance' => $receiver->balance + 100 + ]); + }); + ## Debugging From a665a89440aaedb91c66becc2f1b3b79eb3c3b6b Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 15 Jan 2025 13:53:41 -0600 Subject: [PATCH 2/2] Update queries.md --- queries.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/queries.md b/queries.md index ff746a9a845..4114fff698b 100644 --- a/queries.md +++ b/queries.md @@ -1191,7 +1191,7 @@ Alternatively, you may use the `lockForUpdate` method. A "for update" lock preve ->lockForUpdate() ->get(); -It is recommended, but not obligatory, to wrap pessimistic locks inside a [transaction](/docs/{{version}}/database#database-transactions), especially when you require the data retrieved not to be altered on the database until the entire logic is executed. In case of failure, the locks will be freed and any changes will be rolled back. +It is recommended, but not obligatory, to wrap pessimistic locks inside a [transaction](/docs/{{version}}/database#database-transactions), especially when you require the data retrieved to not be altered on the database until the entire transaction is finished. If the transaction fails, the locks will be freed and any changes will be rolled back: DB::transaction(function () { $sender = DB::table('users') @@ -1203,7 +1203,7 @@ It is recommended, but not obligatory, to wrap pessimistic locks inside a [trans ->find(2); if ($user->balance < 100) { - throw new RuntimeException('The sender has not enough balance'); + throw new RuntimeException('Balance too low.'); } DB::table('users')