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!

Как это обойти?

Author: John Smith, 2014-07-23

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);
 6
Author: Brad, 2014-07-23 18:51:12

Функция, которую вы ищете, upsert: если существует, то обновите, иначе вставьте.

Mysql поддерживает их: http://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html

 3
Author: Andreas, 2014-07-23 18:51:22