У меня есть таблица «очков» со столбцом «игрок» и столбец «fpp», представляющий некоторый расходный тип очков.
Мне нужна функция, которая будет вычитать x fpp из баланса конкретного игрока, если они имеют> = x fpp. Функция должна возвращать значение true, если баланс игрока уменьшился, или значение false, если средств было недостаточно.
Мне нужно предотвратить любые случаи двойных расходов, для которых, насколько я могу судить, мне понадобятся транзакции. Используя PDO, я собрал следующее:
function subFPP($player,$x){
global $dbh;
$didSub = false;
$dbh->beginTransaction();
$stmt = $dbh->prepare("SELECT fpp FROM points WHERE player=?");
$stmt->execute(array($player));
$row = $stmt->fetch();
if($row && $row[0]>=$x){
$stmt = $dbh->prepare("UPDATE points SET fpp=fpp-? WHERE player=?");
$stmt->execute(array($x,$player));
$didSub = true;
}
if($dbh->commit()){
return $didSub;
}
return false;
}
Кажется, это ведет себя как задумано, но я никогда раньше не работал с транзакциями, и я не совсем уверен, что это делает то, что мне нужно. Если для этой функции одновременно выполняются два вызова, должен пройти только один (при условии, что x больше половины доступного баланса). Это защитит меня от двойных расходов или я что-то напортачил? Какие-нибудь улучшения?
Кроме того — все фрагменты транзакций PDO, которые я видел, окружены try / catch и включают вызов rollBack в блоке ошибок. Там нет причин для отката здесь для одной вставки / обновления?
Задача ещё не решена.
Других решений пока нет …