Увеличивает ли поле в MySQL атомарный? - PullRequest
32 голосов
/ 05 декабря 2010

Я создаю веб-сайт, на котором я хотел бы увеличить счетчик в стандартной таблице MyISAM.

Упрощенный пример:

UPDATE votes SET num = num + 1;

Приведет ли это к проблемам, если несколько соединений выполняют один и тот же запрос, или MySQL позаботится об этом и заблокирует таблицу или что-то еще, чтобы убедиться в отсутствии конфликтов?

Ответы [ 6 ]

23 голосов
/ 15 марта 2011

Запись является атомарной, но приращение также требует чтения. Итак, вопрос: вы уверены, что чтение безопасно, другими словами, вы уверены, что другой поток, выполняющий инкремент, не будет иметь такое же значение, которое будет увеличено? У меня есть сомнения. 100% правильный способ сделать это будет.

-- begin transaction here

select counter from myCounters where counter_id = 1 FOR UPDATE;

-- now the row is locked and nobody can read or modify its values

update myCounters set counter = ? where id = 1;

-- set ? to counter + 1 programmatically

commit; -- and unlock...
14 голосов
/ 05 декабря 2010

В таблицах MyISAM используется блокировка на уровне таблицы. Это означает, что вся таблица будет заблокирована во время выполнения вашего запроса на обновление. Таким образом, ответ для вашего упрощенного варианта использования: да, это потокобезопасно. Но это может быть не так, если вы используете другой механизм хранения или ваше обновление содержит несколько таблиц.

Вот цитата из руководства MySQL для большей ясности:

Блокировка таблицы позволяет многим сеансам читать из таблицы одновременно, но если сеанс хочет написать в стол, он должен сначала получить эксклюзив доступ. Во время обновления все остальные сеансы, которые хотят получить доступ к этому конкретная таблица должна ждать, пока обновление завершено.

Вы также можете рассмотреть возможность использования автоинкрементных столбцов, транзакций или внешней синхронизации, если это соответствует вашему дизайну.

Ура!

5 голосов
/ 05 декабря 2010

Да, таблица (или строки в базах данных формата InnoDB) автоматически блокируется при выполнении запроса на обновление.

4 голосов
/ 05 декабря 2010

Эта форма UPDATE является атомарной. Другие формы UPDATE можно сделать атомарными, используя транзакции с SELECT ... FOR UPDATE.

2 голосов
/ 06 марта 2012

Возникла та же проблема, хотя запрос был более сложным:

UPDATE CLB_SYNC_T SET PENDING_MESSAGES = PENDING_MESSAGES + ? WHERE USER_ID = ?

Использование MyISAM в качестве механизма по умолчанию не помогло, поэтому я вернулся к ВЫБРАТЬ ДЛЯ ОБНОВЛЕНИЯ use.

С SELECT FOR UPDATE производительность улучшена в ~ 10 раз, поскольку MySQL не блокировал всю таблицу, чтобы выполнить обновление строки.

0 голосов
/ 19 января 2015

Другой подход при использовании InnoDB заключается в использовании уникального индекса для нескольких столбцов следующим образом:

Таблица «Сессии» { unique_key (browser_session_id, profile_id) // гарантирует, что вставка 1 записи за сеанс произойдет один раз }

выбор количества (browser_session_id) из сеансов

Гарантирует результат уникальных сеансов, так как несколько сеансов на пользователя не допускаются.

Выводы

  • Преимущество

    Каждая вставка требует предварительного выбора.

  • Неудобство

    Подходит не для всех случаев.

    Может замедлить производительность записи и требует дополнительного управления

...