2016-11-22 6 views
1

Ich habe Tabelle tt_users die id als Primärschlüssel und Spalten state (CHAR (1)), kann die "x" oder "y" und state_position (INT) sein. Für diese Spalten gibt es keine Indizes. Speichermodul ist innodb.MySQL - Deadlock gefunden, wenn sie versuchen zu sperren zu bekommen

state_positions muss immer in Folge sein, und es kann nie eine doppelte Position für einen bestimmten Zustand, das heißt, wenn ich 5 Benutzer mit state ‚x‘ haben, müssen ihre state_positions sein 1,2,3,4,5

Dies ist die Abfrage ich renne, die Deadlocks Ursachen:

insert into `tt_users` (`state`, `state_position`) 
values ('x', 
    (SELECT MAX(state_position) AS maxStatePosition 
    FROM tt_users AS u2 
    WHERE u2.state='x') + 1 
) 

Zum Testen eingefügt ich eine große Anzahl an Benutzern gleichzeitig, und jedes Mal, wenn ich bekam die Deadlockfehler.

Ich habe diesen Beitrag gelesen - How to avoid mysql 'Deadlock found when trying to get lock; try restarting transaction' aber ich habe nicht verstanden, was ich mit meiner Abfrage tun sollte, um Deadlocks zu verhindern, wenn das überhaupt möglich ist, da die Antwort auf diese Frage - Working around MySQL error "Deadlock found when trying to get lock; try restarting transaction" - Deadlocks passieren kann, egal was .

Die einzige Art, wie ich es geschafft, dies, zur Arbeit zu kommen und konsequent arbeiten, ist diese (Sprache PHP):

PDO::setAttribute(PDO::ATTR_EMULATE_PREPARES, true); 

Dann manuell die Tabellensperren und läuft meine Frage:

SET autocommit=0; 

LOCK TABLES 
tt_users WRITE, 
tt_users AS u2 WRITE; 

insert into `tt_users` (`state`, `state_position`) 
values ('x', 
    (SELECT MAX(state_position) AS maxStatePosition 
    FROM tt_users AS u2 
    WHERE u2.state='x') + 1 
); 

COMMIT; 
UNLOCK TABLES; 

Und dann:

PDO::setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 

Mit dieser Methode, die ich den Code 4 mal gleichzeitig lief, jede Instanz inser 2500 Benutzer, ohne Probleme.

Ist dies der einzige Weg, um dies zum Laufen zu bringen, oder kann ich mit hundertprozentiger Sicherheit Deadlocks verhindern, ohne die Tabelle manuell sperren zu müssen?

UPDATE:

Pro @ wallyk Antwort, habe ich versucht, die folgenden:

1) die Abfrage in einer Transaktion Einlochen - Deadlock noch Fehler
2) Starten der Transaktion mit WITH CONSISTENT SNAPSHOT, READ WRITE, READ ONLY. Alle 3 Optionen müssen PDO::setAttribute(PDO::ATTR_EMULATE_PREPARES, true); eingestellt werden. WITH CONSISTENT SNAPSHOT und READ WRITE gab mir immer noch Deadlock-Fehler, während READ ONLY natürlich nicht einmal erlauben, dass ich die INSERT ausführen.

So für den Moment scheint es manuell Sperren der Tabelle ist die einzige Sache, die funktioniert.

Antwort

0

Ich weiß nicht, ob es helfen wird, aber mit einer Transaktion, die die SQL-Anweisung umgibt, kann die korrekte Schließfolge intern bieten:

start transaction; 
insert into `tt_users` (`state`, `state_position`) 
values ('x', 
    (SELECT MAX(state_position) AS maxStatePosition 
    FROM tt_users AS u2 
    WHERE u2.state='x') + 1 
); 
commit; 

Wenn das nicht funktioniert, gibt es ein paar Optionen sind die kann zur start transaction Aussage hinzugefügt werden. Siehe here.

+0

Danke, ich werde alle diese versuchen und mit Ergebnissen zurückkommen. – GTCrais

+0

Aktualisierte Frage mit Ergebnissen, nachdem Sie Ihren Vorschlag ausprobiert haben. Leider hat es nicht funktioniert. – GTCrais

Verwandte Themen