Php, "потокобезопасная" операция SQL
Давайте поговорим о рейтинговой системе: пользователи могут оценивать других пользователей. Существует таблица user
: ИДЕНТИФИКАТОР ПОЛЬЗОВАТЕЛЯ, ИМЯ ПОЛЬЗОВАТЕЛЯ и rates
: ИДЕНТИФИКАТОР РЕЙТИНГА, идентификатор РЕЙТИНГА, РЕЙТИНГ (строка)
Пользователь может оценить кого-то один раз, но может изменить свое мнение в любое время
Я знаю, что это немного странно, этого никогда не может случиться, но давайте посмотрим, как все пойдет:
check if A ever rated B
if no: INSERT INTO
if yes: UPDATE
Итак, в псевдокоде:
$rec = SELECT COUNT(*) FROM users WHERE RATER_ID = a AND RATED_ID = b
if ($rec == 0)
{
INSERT INTO rates (a, b, rateText);
}
else
{
UPDATE rates SET RATE = rateText WHERE RATER_ID = a AND RATER_ID = b
}
Но здесь возникает проблема. Предположим, что две ставки поступают одновременно (я знаю, что это странно).
- rate request A: count(*) is 0, so lets insert
- rate request B: count(*) is 0, so lets insert - SQL ERROR!
Как это обойти?
2 answers
То, что вам нужно, обычно известно как операция "upsert". То есть UPDATE
, если он уже есть, в противном случае INSERT
.
Вы можете установить ограничение UNIQUE
для ваших столбцов RATER_ID
, RATED_ID
. Таким образом, одновременно с этой конкретной комбинацией может существовать только одна строка.
Оттуда используйте INSERT... ON DUPLICATE KEY
. http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
Непроверенный, но что-то вроде этого:
INSERT INTO rates (a, b, rateText) VALUES (:a, :b, :rateText)
ON DUPLICATE KEY UPDATE rateText=VALUES(rateText);
Функция, которую вы ищете, upsert
: если существует, то обновите, иначе вставьте.
Mysql поддерживает их: http://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html