почему вставка на столе заблокирована? - PullRequest
0 голосов
/ 14 марта 2019

Я пытаюсь что-то с уровнями транзакций на MySQL.

У меня есть Сессия S1 и Сессия S2. S1 работает с изоляцией по умолчанию lavel Repeatable Read. Для S2 я устанавливаю сериализуемый уровень изоляции.

Вот сценарий:

S1:

set innodb_lock_wait_timeout = 5;
start transaction;

S2:

set session transaction isolation level serializable;
start transaction;
select count(*) from produkt;

S1:

select count(*) from produkt;
update kategorie set bezeichnung = 'Smartphone' where kategorieid = 1;

S2:

 insert into produkt(produktid, bezeichnung, kategorieid_fk) values (201, 'iPhone 8z', 1);

Может кто-нибудь объяснить, почему insert into produkt из S2 теперь заблокирован?

Вот таблица:

    -- Exportiere Datenbank Struktur für transaktiondb
    CREATE DATABASE IF NOT EXISTS `transaktiondb`;
    USE `transaktiondb`;


    -- Exportiere Struktur von Tabelle transaktiondb.kategorie
    CREATE TABLE IF NOT EXISTS `kategorie` (
      `KategorieID` int(11) NOT NULL AUTO_INCREMENT,
      `Bezeichnung` varchar(255) NOT NULL,
      PRIMARY KEY (`KategorieID`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    -- Exportiere Struktur von Tabelle transaktiondb.produkt
    CREATE TABLE IF NOT EXISTS `produkt` (
      `ProduktID` int(11) NOT NULL AUTO_INCREMENT,
      `Bezeichnung` varchar(255) NOT NULL,
      `KategorieID_FK` int(11) NOT NULL,
      PRIMARY KEY (`ProduktID`),
      KEY `fk_Produkt_Kategorie_idx` (`KategorieID_FK`),
      CONSTRAINT `fk_Produkt_Kategorie` FOREIGN KEY (`KategorieID_FK`) REFERENCES `kategorie` (`KategorieID`) ON DELETE NO ACTION ON UPDATE NO ACTION
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1 Ответ

0 голосов
/ 15 марта 2019

У вас есть тупик , который MySQL описывает как:

Ситуация, когда разные транзакции не могут быть выполнены, поскольку каждая из них содержит блокировку, необходимую для другой. Поскольку обе транзакции ожидают, когда ресурс станет доступным, ни одна из них никогда не снимет блокировки, которые он удерживает.

Присмотревшись к Как минимизировать и справиться с тупиками читает:

InnoDB использует автоматическую блокировку на уровне строк. Вы можете получить взаимоблокировки даже в случае транзакций, которые просто вставляют или удаляют одну строку. Это потому, что эти операции на самом деле не являются «атомарными»; они автоматически устанавливают блокировки на (возможно несколько) индексных записей вставленной или удаленной строки.

Что касается характера innodb_lock_wait_timeout, в документации описывается, что он применяется только к сценариям, в которых inno_db_detect отключен, что не является конфигурацией по умолчанию:

Значение времени ожидания блокировки не применяется к взаимоблокировкам, когда innodb_deadlock_detect включен (по умолчанию), поскольку InnoDB немедленно обнаруживает взаимоблокировки и откатывает одну из взаимоблокированных транзакций. Когда innodb_deadlock_detect отключен, InnoDB полагается на innodb_lock_wait_timeout для отката транзакции при возникновении взаимоблокировки. См. Раздел 14.7.5.2, «Обнаружение тупиковой ситуации и откат».

Также, в качестве общего совета, вы часто будете хотеть использовать start transaction, за которым следует как можно быстрее commit или rollback, и не оставлять сеанс "зависшим", чтобы минимизировать эти проблемы.

...