MySQL: Wird eine Transaktion die Zeile sperren?


13

Ich habe noch nie versucht, eine MySQL-Transaktion zu verwenden. Ich möchte nur etwas klarstellen.

Wenn zwei Benutzer genau zum richtigen Zeitpunkt eine Abfrage ausführen, wie würde MySQL damit umgehen? Beispiel: Der Benutzer versucht, einen Datensatz zu aktualisieren.

Benutzer1: Tabellensatz aktualisieren column = column - 4 wobei column_id = 1;

Benutzer2: Aktualisiere Tabellensatz column = column - 7 wobei column_id = 1;

Wenn ich nun Transaktionen verwende, wählt MySQL dann aus, welche Abfrage zuerst ausgeführt wird, und sperrt den zweiten Benutzer, bis die erste Abfrage festgeschrieben wird? Wird das eine Tabellensperre oder eine Zeilensperre sein?

Was ist, wenn ein dritter Benutzer eine select-Anweisung ausgibt? Welchen Wert wird MySQL zurückgeben?

PS das wird auf Innodb sein.

Antworten:


16

Eine einzelne Anweisung wie diese funktioniert genauso mit MyISAM oder InnoDB, mit einer Transaktion oder mit autocommit = ON. Es blockiert genug, um die Abfrage durchzuführen, wodurch die andere Verbindung blockiert wird. Wenn Sie fertig sind, wird die andere Verbindung fortgesetzt. In allen Fällen wird die Spalte bald um 11 dekrementiert.

Ein dritter Benutzer kann sehen, dass der Wert um 0 oder 4 oder 7 oder 11 dekrementiert wird. Die "sehr genaue Zeit" ist nicht wirklich möglich, da zu einem bestimmten Zeitpunkt bei der Ausführung jeder Anweisung eine Single-Threaded-Sperre aktiviert / gesetzt / was auch immer ist . Das heißt, sie werden serialisiert werden, nur so schnell , dass man es nicht sehen kann.

InnoDB sperrt nur Zeilen, keine Tabellen. (OK, DDL-Anweisung macht mutigere Sperren.)

Interessanter wird eine Transaktion, die zwei Dinge ändert oder die spürbar viel Zeit in Anspruch nimmt:

Absichtsfall: Einzelstück, aber Zeit in Anspruch:

BEGIN;
SELECT something;
think about it for a while
UPDATE that something;
COMMIT;

Die Auswahl muss folgendermaßen geschrieben werden:

SELECT something  FOR UPDATE;

Dies sagt anderen Verbindungen "Ich beabsichtige, die Zeile zu aktualisieren; bitte vermasseln Sie mich nicht". (Ich spreche dieses Beispiel an, weil viele Neulinge diese Subtilität vermissen.)

Deadlock-Fall: Mit 2 Dingen herumspielen:

BEGIN;    -- in one connection
UPDATE thing_1;
UPDATE thing_2;
COMMIT;

BEGIN;    -- in another connection, at the "exact same time"
UPDATE thing_2;
UPDATE thing_1;
COMMIT;

Dies ist das klassische Beispiel für einen Deadlock - jeder greift nach einer Sache und greift dann nach der anderen. Es ist klar, dass es nicht zum Laufen gebracht werden kann. Eine Transaktion wird beendet. der andere vervollständigt. Daher müssen Sie nach Fehlern suchen, damit Sie sie entdecken können.

Die normale Reaktion auf einen Deadlock besteht darin, die gesamte fehlgeschlagene Transaktion erneut abzuspielen. Bis dahin wird die andere Verbindung nicht stören und sollte ohne Probleme fortgesetzt werden. (OK, eine weitere Verbindung könnte einen weiteren Deadlock verursachen.)

Verzögerungsfall: Wenn die beiden Verbindungen mehrere Dinge in derselben Reihenfolge erfassen, kann eine verzögert werden, bis die andere beendet ist. Damit dies nicht "ewig wartet", gibt es eine Standardeinstellung von 50 Sekunden innodb_lock_wait_timeout. Ihr einfaches Paar UPDATEsist tatsächlich ein Beispiel für diesen Fall. Man wird sofort fertig sein; der andere bleibt stehen, bis der erste fertig ist.

Beachten Sie, wie ein Deadlock (in einigen Fällen) in eine Verzögerung umgewandelt werden kann, indem Sie die Dinge, die Sie berühren, konsequent anordnen.

autocommit = 1: Mit dieser Einstellung und ohne Aufruf BEGINist jede Anweisung effektiv:

BEGIN;
your statement
COMMIT;

autocommit = 0: Dies ist ein Problem, das darauf wartet, passiert zu werden. Wenn Sie eine Schreibabfrage ausführen, BEGINwird implizit a generiert. Es liegt jedoch in Ihrer Verantwortung, eventuell etwas herauszugeben COMMIT. Wenn Sie dies nicht tun, werden Sie sich fragen, warum Ihr System hängen bleibt. (Ein weiterer häufiger Fehler für Neulinge.) Mein Rat: "Niemals verwenden =0".

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.