Как правильно организовать транзакцию перевода внутрисайтовой валюты между пользователями в laravel?

Пользователь отправляет запрос на сервер о переводе части средств со своего счета на счет другого пользователя.
На уровне базы данных поле balance у каждого пользователя: unsignedInteger
Происходит валидация запроса:
$this->validate($request, [
   'receiver_id'=>'required',
   'money'=>'required|integer',
]);

Далее выполняется транзакция:
DB::transaction(function () use ($request) {
    //Снимаем деньги со счета пользователя 
    User::where('id', Auth::user()->id)->decrement('balance', $request->money); 
    //Переводим деньги другому пользователю
    User::where('id', $request->receiver_id)->increment('balance', $request->money);
    //Добавляем в бд запись о транзакции
    $transaction = MoneyTransaction::create($request->all() + ['sender_id' => Auth::user()->id, 'type_id' => 2]);
});

1) Правильно ли организована структура транзакции?
2) Нужно ли проверять, что у пользователя достаточное количество денег на счету (больше чем $request->money) если поле balance в базе данных unsignedInteger?
3) Если да, то это нужно делать в самой транзакции?
4) И нужно ли использовать какие-либо блокировки sharedLock/lockForUpdate?
Заранее спасибо!
  • Вопрос задан
  • 798 просмотров
Решения вопроса 1
@miki131
DB::transaction(function () use ($request) {
            $user = User::where('id', Auth::user()->id)->lockForUpdate()->first();
            if ($user->balance < $request->money) {
                throw new \Exception('Insufficient funds');
            }
            //Снимаем деньги со счета пользователя 
            $user->decrement('balance', $request->money);
            //Переводим деньги другому пользователю
            User::where('id', $request->receiver_id)->increment('balance', $request->money);
            //Добавляем в бд запись о транзакции
            $transaction = MoneyTransaction::create($request->all() + ['sender_id' => $user->id, 'type_id' => 2]);
        });
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы