@aopil

Как правильно списать баланс в базе?

При десятках одновременных запросах баланс пользователя списывается не правильно.

Гуглил, изучал, читал, как я понял для этого используют транзакции.

Накинул такой код:
<?php 
try {
	$objDBCD14->autocommit(false);
	$objDBCD14->begin();
	$rsMyCredits = $objDBCD14->queryUniqueObject("SELECT Balance FROM tbl_users WHERE UserId = '" . $rs->UserId . "'");

	$myCredits = somedecrypt($rsMyCredits->Balance);
	$finalBalance = $myCredits - $servicePrice;
	$encryptedCredits = someencrypt($finalBalance);

    $objDBCD14->execute("INSERT INTO tbl_credit_history SET UserId = '" . $rs->UserId . "', Credits = '" . $servicePrice . "', HistoryDtTm = '" . $currDtTm . "', CreditsLeft = '" . $encryptedCredits . "'");
    $objDBCD14->execute("UPDATE tbl_users SET Credits = '" . $encryptedCredits . "' WHERE UserId = '" . $rs->UserId . "'");

    $objDBCD14->commit();
    $objDBCD14->autocommit(true);

} catch (Exception $e) {
	$objDBCD14->rollback();
}
?>


Но проблема как была, так и есть. Да, знаю, что баланс пользователя лучше считать напрямую в SQL запросе, но в данной ситуации баланс пользователя закодирован некой функцией, как вы можете видеть по коду.

Вопрос: Как же все таки решается эта проблема? Транзакциями? тогда что я делаю не так?

6204323b1b664372327939.png
  • Вопрос задан
  • 159 просмотров
Решения вопроса 1
@galaxy
Начните вот с этого:
$rsMyCredits = $objDBCD14->queryUniqueObject(
    "SELECT Balance FROM tbl_users WHERE UserId = '" . $rs->UserId . "' FOR UPDATE"
);
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
PavelK
@PavelK
Похоже больше на гонку - когда запрос A приходит позже запроса B.
Решаются такие проблемы индивидуально, в зависимости от остальной архитектуры грубо говоря ичего-то универсального тут нет.
Касаемо Вашей ситуации, мне лично непонятно, каким образом очерёдность запросов может повлиять на результат, т.к. в моём понимании текущей ситуации баланс это либо сложение либо вычитание, и ничего особо страшного не будет, если будет -1 -2 -3 +10 а не +10 -1 -2 -3 итог то будет один.

Можете слать баланс ДО и какой должен быть ПОСЛЕ и все изменения проводить скажем раз в N секунд, а до этого просто всё собирать в некую очередь для дальнейшей сортировки/понимания кто что делает и когда, во время которой отказывать в запросах, если выполнение долгое и т.д.
Ответ написан
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы
YCLIENTS Москва
от 200 000 до 350 000 ₽
Ведисофт Екатеринбург
от 25 000 ₽
ИТЦ Аусферр Магнитогорск
от 100 000 до 160 000 ₽