Как не допустить двойную трату денег на балансе пользователя?

В сайте существуют 2 таблицы

balances
id, owner_id, total

и

orders
id, product_id, price, created_timestamp

Пользователь заходит на сайт и нажимает под каким-то товаром кнопку купить, отправляется запрос на сервер, он обрабатывается скриптом php

в этом коде есть фрагмент

$query = pg_query("SELECT total from balances where owner_id = '$user_id'  LIMIT 1;");
    $total = pg_fetch_array($pg_query($query))[0];
    
    if ($total >= $product_price){
        $query = "UPDATE balances set total = total-'$product_price' where owner_id = '$user_id';
    INSERT into orders (product_id, price, created_timestamp) VALUES ('$product_id','$product_price','$timestamp');";
    }

мне кажется этот фрагмент кода может стать уязвимостью в сайте,в случае если пользователь быстро отправит условную 1000 запросов к серверу, то т.к. эти запросы обрабатываются параллельно, то несколько запросов могут получить баланс пользователя до его изменения и в итоге могут создаться два и более заказов, а баланс пользователя уйдёт в минус

мои знания в как в базах , так и в языках программирования достаточно скромны, поэтому мне не приходит в голову ни одного решения кроме как создания сервиса, с которым этот скрипт будет соединяться, чтобы передать запрос. А этот сервис уже проверяет балансы и добавляет заказы, используя только один поток этот вариант мне не очень нравится, тк это очень сильно режет максимальную нагрузку на сайт

хотелось бы каким-то образом заблокировать строку балансов этого пользователя для чтения и изменения одним и тем же запросом с SELECT total и разблокировать только после вычитания цены товара

Возможно ли это как-то сделать или подойдёт какой-то другой способ?


Ответы (0 шт):