508 MySQL - Technische Referenz f¨ur Version 5.0.1-alpha
anderen Benutzers geh¨oren, wird gewartet, bis die Transaktion a/jointfilesconvert/293675/bgeschlossen (committed)
ist. Eine Shared-Modus-Sperre verhindert, dass andere die Zeile aktualisieren oder l¨oschen,
die gerade gelesen wurde. Nachdem festgestellt wurde, dass die obige Anfrage die Eltern
’Hinr’ zur¨uckgibt, kann das Kind sicher zur Tabelle kind hinzugef¨ugt und die Transaktion
a/jointfilesconvert/293675/bgeschlossen werden. Dieses Beispiel zeigt, wie Sie in Ihren Applikations-Code referentielle
Integrit¨at integrieren k¨onnen.
Sehen wir uns ein weiteres Beispiel an. Wir haben ein ganzzahliges Z¨ahlerfeld in einer
Tabelle kind_codes, was benutzt wird, um jedem Kinde, das wir der Tabelle kind
hinzuf¨ugen, eine eindeutige Kennung zuzuweisen. Es ist offensichtlich, dass Konsistentes
Lesen oder Shared-Modus-Lesen kein geeignetes Mittel ist, um den aktuellen Wert des
Z¨ahlers zu ermitteln, weil n¨amlich zwei Benutzer der Datenbank denselben Wert des
Z¨ahlers sehen k¨onnen und wir daher einen Fehler wegen doppelter Schl¨usseleintr¨age
erhalten, wenn wir zwei Kinder mit derselben Kennung in die Tabelle einf¨ugen.
In diesem Fall gibt es zwei geeignete M¨oglichkeiten, das Lesen und Heraufz¨ahlen des Z¨ahlers
zu implementieren: (1) Zuerst den Z¨ahler um eins erh¨ohen und erst danach lesen. (2) Zuerst
den Z¨ahler im Sperr-Modus FOR UPDATE lesen und danach heraufz¨ahlen:
SELECT COUNTER_FIELD FROM kind_codes FOR UPDATE;
UPDATE kind_codes SET COUNTER_FIELD = COUNTER_FIELD + 1;
SELECT ... FOR UPDATE liest die letzten verf¨ugbaren Daten und setzt exklusive Sperren auf
jede Zeile, die es liest. Daher setzt es dieselben Sperren, die ein gesuchtes SQL-UPDATE auf
die Zeilen setzen w¨urde.
8.5.8.3 N¨achsten Schl¨ussel sperren: Wie das Phantom-Problem
vermieden wird
Beim Sperren auf Zeilenebene benutzt InnoDB einen Algorithmus, der N¨achsten-Schl¨ussel-
Sperren genannt wird. InnoDB f¨uhrt das Sperren auf Zeilenebene so durch, dass es beim
Suchen oder Scannen eines Indexes auf eine Tabelle gemeinsam genutzte (shared) oder
exklusive Sperren auf die Index-Datens¨atze setzt, die es findet. Daher werden die Sperren
auf Zeilenebene genauer Index-Datensatz-Sperren genannt.
Die Sperren, die InnoDB auf Index-Datens¨atze setzt, betreffen auch die ’L¨ucke’ vor diesem
Index-Datensatz. Wenn ein Benutzer eine gemeinsam benutzte (shared) oder exklusive
Sperre auf den Datensatz R in einem Index hat, kann ein anderen Benutzer keinen Daten-
satz direkt vor R (in der Index-Reihenfolge) einf¨ugen. Dieses Sperren von L¨ucken wird
durchgef¨uhrt, um das so genannte Phantom-Problem zu vermeiden. Angenommen, man
will alle Kinder aus der Tabelle kind lesen und sperren, die eine Kennung gr¨oßer 100 haben,
und irgend ein Feld in der ausgew¨ahlten Zeile aktualisieren:
SELECT * FROM kind WHERE ID > 100 FOR UPDATE;
Angenommen, es gibt einen Index auf der Tabelle kind auf der Spalte ID. Unsere Anfrage
scannt diesen Index ab dem ersten Datensatz, bei dem ID gr¨oßer als 100 ist. Wenn jetzt
die auf den Index-Datensatz gesetzten Sperren nicht Einf¨ugeoperationen sperren w¨urden,
die in die L¨ucken ausgef¨uhrt w¨urden, k¨onnte zwischenzeitlich ein neues Kind in die Tabelle
eingef¨ugt werden. Wenn jetzt unsere Transaktion noch einmal folgendes ausf¨uhren w¨urde:
SELECT * FROM kind WHERE ID > 100 FOR UPDATE;
Kommentare zu diesen Handbüchern