Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Unerwartete Sperrung für Tabelle mit Primärschlüssel und eindeutigem Schlüssel

Das Problem, auf das Sie stoßen, tritt auf, weil MySQL nicht nur die Tabellenzeile für einen Wert sperrt, den Sie einfügen werden, sondern alle möglichen Werte zwischen der vorherigen id und die nächste ID in der Reihenfolge, also unter Wiederverwendung Ihres Beispiels unten:

DROP TABLE IF EXISTS foo;
CREATE TABLE `foo` (
  `i` INT(11) NOT NULL,
  `j` INT(11) DEFAULT NULL,
  PRIMARY KEY (`i`),
  UNIQUE KEY `jk` (`j`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
INSERT INTO foo VALUES (5,5), (8,8), (11,11);

Angenommen, Sie beginnen mit Transaktion TX1:

START TRANSACTION;
REPLACE INTO foo VALUES(8,8);

Dann starten Sie eine Transaktion TX2 , egal INSERT oder REPLACE mit einer id zwischen 5 und 11 wird gesperrt:

START TRANSACTION;
REPLACE INTO foo VALUES(11,11);

Anscheinend verwendet MySQL diese Art von Sperren, um das hier beschriebene „Phantomproblem“ zu vermeiden:http://dev.mysql.com/doc/refman/5.0/en/innodb-next-key-locking.html , verwendet MySQL ein „Next-Key-Locking“, das das Sperren von Indexzeilen mit dem Sperren von Lücken kombiniert. Dies bedeutet für uns, dass es viele mögliche IDs zwischen der vorherigen und der nächsten ID sperren wird und auch die vorherige und die nächste ID sperren wird .

Um dies zu vermeiden, versuchen Sie, einen Serveralgorithmus zu erstellen, der Ihre Datensätze so einfügt, dass Datensätze, die in verschiedene Transaktionen eingefügt werden, sich nicht überlappen, oder zumindest nicht alle Ihre Transaktionen gleichzeitig ausführen, also TX müssen nicht aufeinander warten.