Подтвердить что ты не робот

Как убедиться, что в базе данных MySQL нет условий гонки при добавлении поля?

Как предотвратить состояние гонки в базе данных MySQL, когда два соединения хотят обновить одну и ту же запись?

Например, соединение 1 хочет увеличить счетчик "попыток". И второе соединение хочет сделать то же самое. Оба соединения SELECT подсчитывают "попытки", увеличивают значение и оба UPDATE "пробуют" с увеличенным значением. Внезапно "пытается" только "пытается + 1" вместо "try + 2", потому что оба соединения получили одинаковые "попытки" и увеличили его на единицу.

Как решить эту проблему?

4b9b3361

Ответ 1

Здесь три разных подхода:

Атомное обновление

update table set tries=tries+1 where condition=value;

и это будет сделано атомарно.

Использовать транзакции

Если вам нужно сначала выбрать значение и обновить его в своем приложении, вам, вероятно, потребуется использовать транзакции. Это означает, что вам придется использовать InnoDB, а не таблицы MyISAM. Ваш запрос будет выглядеть примерно так:

BEGIN; //or any method in the API you use that starts a transaction
select tries from table where condition=value for update;
.. do application logic to add to `tries`
update table set tries=newvalue where condition=value;
END;

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

Схема версии

Общим подходом является введение столбца версии в вашу таблицу. Ваши запросы будут делать что-то вроде:

select tries,version from table where condition=value;
.. do application logic, and remember the old version value.
update table set tries=newvalue,version=version + 1 where condition=value and version=oldversion;

Если это обновление выходит из строя/возвращает 0 строк, кто-то еще обновил таблицу в среднем времени. Вы должны начать все сначала, то есть выбрать новые значения, выполнить логику приложения и снова попробовать обновление.

Ответ 2

Используйте один оператор вместо двух. Один оператор UPDATE, который выполняет чтение и запись, будет атомарным и не будет конфликтовать с другим одновременным обновлением.

UPDATE table SET tries = tries + 1 WHERE ...

Или вы можете использовать транзакции, чтобы сделать две операции атомарными.

BEGIN
SELECT ...
UPDATE ...
COMMIT

Или, более примитивно, заблокируйте таблицу, пока вы ее читаете/записываете.

LOCK TABLES table WRITE
SELECT ...
UPDATE ...
UNLOCK TABLES

Ответ 3

Я предлагаю вам найти тему: функция "Заблокировать таблицу" Mysql. Блокировка таблицы позволяет решить такую ​​ситуацию.