2010-12-05 3 views
26

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

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

UPDATE votes SET num = num + 1; 

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

+0

Вы также можете быть заинтересованы в моем ответе на другой вопрос запирающего: http://stackoverflow.com/questions/3312361/does-this-lock -the-database/3312790 # 3312790 – Mike 2010-12-05 13:52:25

ответ

12

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

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

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

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

Cheers!

3

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

4

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

18

Запись является атомной, но приращение также требует считывания. Поэтому возникает вопрос: уверены ли вы, что чтение безопасно, другими словами, вы уверены, что другой поток, выполняющий приращение, не будет иметь такое же значение, которое нужно увеличить? У меня есть сомнения. 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... 
+1

Я достаточно уверен, что пример OPs поля UPDATE SET = поле + 1 не вызовет проблем с параллелизмом, но это лучший способ гарантировать, что вы блокируете строку/таблицу при изменении поле. Обычно имеет смысл, если вы выполняете более сложную операцию. – Nicholi 2013-05-09 19:46:48

0

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

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

Использование MyISAM в качестве двигателя по умолчанию не помогло, так что я Откат к ИЗБРАННЫЕ UPDATE использования.

С ВЫБОР ДЛЯ ОБНОВЛЕНИЯ производительность улучшена ~ 10 раз, так как MySQL не заблокировала целую таблицу, чтобы сделать обновление строки.

0

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

Таблица 'Sessions' { unique_key (browser_session_id, profile_id) // гарантирует, что вставка 1 вход на сессии будет происходить один раз }

выберите отсчет (browser_session_id) из сессий

будет гарантировать г из-за уникальных сеансов, поскольку несколько сеансов на пользователя не разрешены.

Выводы

  • Advantage

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

  • Неудобство

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

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