Problemet du upplever beror på att MySQL inte bara låser tabellraden för ett värde du ska infoga, det låser alla möjliga värden mellan föregående id
och nästa id i ordning, så återanvänd ditt exempel nedan:
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);
Anta att du börjar med transaktion TX1:
START TRANSACTION;
REPLACE INTO foo VALUES(8,8);
Sedan om du startar en transaktion TX2
, oavsett INSERT
eller REPLACE
med ett id
mellan 5 och 11 kommer att låsas:
START TRANSACTION;
REPLACE INTO foo VALUES(11,11);
Det verkar som att MySQL använder den här typen av låsning för att undvika "fantomproblemet" som beskrivs här:http://dev.mysql.com/doc/refman/5.0/en/innodb-next-key-locking.html , MySQL använder en "nästa-nyckellåsning", som kombinerar indexradslåsning med gaplåsning, detta betyder för oss att den kommer att låsa många möjliga id mellan föregående och nästa id, och även låsa föregående och nästa id .
För att undvika detta försök skapa en serveralgoritm som infogar dina poster så att poster som infogas i olika transaktioner inte överlappar, eller åtminstone inte kör alla dina transaktioner samtidigt så att TX
behöver inte vänta på varandra.