Вы можете сделать это атомарно, добавив дополнительное условие к запросу и используя mysql_affected_rows()
:
$scCost = $row["gpsc"];
$user_id = mysql_real_escape_string($user_id);
$sql = <<<END
UPDATE member_profile
SET points = points - $scCost
WHERE user_id = $user_id
AND points >= $scCost
END;
mysql_query($sql);
if (mysql_affected_rows() > 0) {
// they can afford it
}
Это значительно лучше, чем сделать SELECT
с последующимUPDATE
, который вводит условие гонки.
Предупреждение: mysql_affected_rows()
возвращает количество строк, которые были изменены .Это важно понимать.Если вы передадите 0 затрат в этот запрос, вы получите:
UPDATE member_profiles SET points = points - 0 ...
mysql_affected_rows()
всегда вернет 0 в этом случае, потому что ни одна строка не была изменена.Поэтому, если значение 0 является допустимым случаем, вам нужно отфильтровать это и вообще не беспокоиться о выполнении запроса.
Также это хорошо работает, если вы обновляете одну строку, но становится немного сложнее, если вы хотитеизменить несколько строк одновременно.Тогда вы попадаете в такие вопросы, как:
- Что если некоторые «строки» могут себе это позволить, а другие нет?
- Хотите ли вы, чтобы все они потерпели неудачу?
- КакВы сообщаете, какие из них не могли себе это позволить?
- Как вы все это делаете атомно?
Возможно, вам лучше всего делать по одному UPDATE
за раз, хотяобычно это не рекомендуемый подход, и, конечно, он не будет масштабироваться до тысяч обновлений одновременно.