Является ли "токены обновления" установленными токенами = токенами + 1 'атомарными в InnoDB?

Без использования явных транзакций:

update tokens set tokens = tokens + 1

гарантированно будет атомарным в InnoDB?

Ответ 1

Я понимаю, что в режиме autocommit (т.е. без явных транзакций) один оператор представляет собой единую транзакцию. Как транзакция на определение атома, поэтому ваш единственный оператор также является атомарным.

Однако, когда дело доходит до оценки ограничений, это не делается на уровне оператора (т.е. транзакции), но строка за строкой, пока оператор обрабатывается.

Если у вас есть уникальное ограничение (индекс) в столбце tokens, это обновление, скорее всего, не удастся из-за этого. То же самое верно для внешних ключей, ссылающихся на одну и ту же таблицу.

Ответ 2

Я думаю, что это не так. Не используйте мои уровни изоляции MySQL/чит-лист, но я думаю, что он будет атомарным на уровне каждой строки (UPDATE будет использовать блокировки интервала IIRC), но не на уровне таблицы.

Теперь более интересный вопрос, чем то, является ли UPDATE атомарным, - это когда неатоматичность UPDATE наблюдаемая. Ответ заключается в том, что одиночные утверждения в уровне изоляции READ UNCOMMITTED могут наблюдать неатомобильность UPDATE, и ряд связанных операторов в одной транзакции в уровне изоляции READ COMMITTED может наблюдать различные обновления. REPEATABLE READ и SERIALIZABLE см. UPDATE, как если бы они были атомарными и согласованными.

Представьте себе две сессии. Session A имеет уровень изоляции SERIALIZABLE и делает: UPDATE tokens SET tokens = tokens + 1 в таблице с 1000 строк.

  • Предположим, что сеанс B имеет уровень изоляции READ UNCOMMITTED и делает SELECT sum(tokens) FROM tokens → Этот выбор может видеть частичное обновление (то есть: некоторые строки обновлены, а другие строки не обновлены).
  • Предположим, что сеанс B имеет уровень изоляции READ COMMITTED и делает SELECT sum(tokens) FROM tokens → Этот select не может видеть частичное обновление, поэтому он видит UPDATE, как если бы он был атомарным.
  • Предположим, что сеанс B имеет уровень изоляции READ COMMITTED и делает SELECT sum(tokens) FROM tokens WHERE id BETWEEN 1 AND 100; SELECT sum(tokens) FROM tokens WHERE id BETWEEN 501 AND 600, а затем какая-то программная логика добавляет эти два значения → Эти SELECT могут видеть различные моментальные снимки MVCC → различные обновления,
  • Предположим, что Session B имеет уровень изоляции REPEATABLE READ и делает SELECT sum(tokens) FROM tokens WHERE id BETWEEN 1 AND 100; SELECT sum(tokens) FROM tokens WHERE id BETWEEN 501 AND 600, а затем какая-то программная логика добавляет эти два значения → Эти SELECT не могут видеть разные снимки MVCC → они видят одно и то же обновление,