admin管理员组文章数量:1242790
I am implementing an API endpoint that allows our users to request a resource from our inventory
table. For simplicity, let's say that the table has a boolean available
column. The idea is that this endpoint will select the first row from the inventory
table where available
is true
, and update that row with the appropriate account ID and setting available
to false
. So it would look something like this:
public function assignItemToAccount(Account $account): Inventory {
$item = Inventory::where('available', true)->first();
$item->update([
'account_id' => $account->id,
'available' => false
]);
return $item->fresh();
}
The problem I'd like to avoid is, since I am using ->first()
, concurrent requests to this endpoint would want to assign the same item from inventory. I see that Laravel supports pessimistic locking via the lockForUpdate
method, but the documentation is sparse, and I'm not sure how to use it in this context – or if this is even the right approach.
I am implementing an API endpoint that allows our users to request a resource from our inventory
table. For simplicity, let's say that the table has a boolean available
column. The idea is that this endpoint will select the first row from the inventory
table where available
is true
, and update that row with the appropriate account ID and setting available
to false
. So it would look something like this:
public function assignItemToAccount(Account $account): Inventory {
$item = Inventory::where('available', true)->first();
$item->update([
'account_id' => $account->id,
'available' => false
]);
return $item->fresh();
}
The problem I'd like to avoid is, since I am using ->first()
, concurrent requests to this endpoint would want to assign the same item from inventory. I see that Laravel supports pessimistic locking via the lockForUpdate
method, but the documentation is sparse, and I'm not sure how to use it in this context – or if this is even the right approach.
1 Answer
Reset to default 1this is how I usually code for database transactions.
<?php
use Illuminate\Support\Facades\DB;
class SomeClass {
public function assignItemToAccount(Account $account)
{
DB::beginTransaction();
try {
$item = Inventory::where('available', true)
->lockForUpdate()
->first();
if (is_null($item)) {
DB::rollBack();
return response()->json(['message' => 'Item not found'], 404);
}
$item->update([
'account_id' => $account->id,
'available' => false
]);
DB::commit();
} catch (\Exception $e) {
\Log::error($e->getMessage());
DB::rollBack();
return response()->json(['message' => 'Failed to assign Item'], 500);
}
return $item->fresh();
}
}
Whenever I think a process needs to have database transactions, I surround them in try catch block.
I prefer using DB::beginTransaction()
over DB::transaction(function () {})
since it has more control over when to commit and rollback.
When using the lockForUpdate()
, it will prevent other process from reading/writing until the initial process commits the database transaction.
So if assignItemToAccount
method is happening at the same time through the request, 1 request is forced to wait until the other completes its transaction.
本文标签: eloquentLaravel 10430 Prevent concurrent requests from updating the same rowStack Overflow
版权声明:本文标题:eloquent - Laravel 10.43.0: Prevent concurrent requests from updating the same row - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1740118830a2227596.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论