Mysql с innodb и сериализуемой транзакцией не всегда блокирует строки - PullRequest
1 голос
/ 12 января 2011

У меня есть транзакция с SELECT и возможно INSERT. По причинам параллелизма я добавил FOR UPDATE к SELECT. Чтобы предотвратить появление фантомных строк, я использую уровень изоляции транзакций SERIALIZABLE. Все это прекрасно работает, когда в таблице есть строки, , но не в том случае, если таблица пуста . Когда таблица пуста, SELECT FOR UPDATE не выполняет (исключительную) блокировку, и параллельный поток / процесс может выдать тот же SELECT FOR UPDATE без блокировки.

CREATE TABLE t (
  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  display_order INT
) ENGINE = InnoDB;

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT COALESCE(MAX(display_order), 0) + 1 from t FOR UPDATE;

..

Эта концепция работает, как и ожидалось, с SQL Server, но не с MySQL. Есть идеи, что я делаю не так?

EDIT

Добавление индекса на display_order не меняет поведение.

Ответы [ 3 ]

1 голос
/ 12 января 2011

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

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

Так что я думаю, что вы, скорее всего, получите исключение взаимоблокировки или исключение тайм-аута довольно быстро, и это должно спасти ситуацию .Но если говорить о идеальной «сериализуемой» ситуации, то это фактически плохой побочный эффект пустой таблицы.Движок не может быть идеальным во всех случаях, по крайней мере, нельзя делать двойные транзакции-вставки ..

Я отправил вчера интересный случай истинной надежности и работоспособности двигателя, в документации по potsgreSQl проверьте этот пример.это забавно : http://www.postgresql.org/docs/8.4/static/transaction-iso.html#MVCC-SERIALIZABILITY

Обновление: Другой интересный ресурс: Реализует ли MySQL / InnoDB истинную сериализуемую изоляцию?

0 голосов
/ 12 января 2011

Это, вероятно, не ошибка.

Способ, которым разные базы данных реализуют определенные уровни изоляции транзакций, НЕ 100% согласован, и существует множество крайних случаев, которые нужно учитывать, которые ведут себя по-разному.InnoDB предназначался для эмуляции Oracle, но даже там, я думаю, есть случаи, когда он работает по-другому.

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

  • Даже если это "работает" прямо сейчас, это может не произойти, если кто-то изменит схему базы данных
  • Маловероятно, что инженеры, обслуживающие ваш код, поймут, как он использует базу данных, если это зависит от тонкостейблокировки
0 голосов
/ 12 января 2011

Вы смотрели на этот документ: http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html

Если вы спросите меня, mysql не был создан для такого использования ... Моя рекомендация: Если вы можете перенести его -> Заблокируйте всю таблицу.

...