2010-10-07 19 views
18

Ich habe eine user Tabelle mit Feld .So sperren Sie eine einzelne Zeile

Ich muss zugreifen und erhöhen .

Während dieser Zugriffszeit muss ich diese bestimmte Benutzerzeile (nicht die gesamte Tabelle) sperren.

Wie mache ich das?

Der Tabellentyp ist MyISAM.

+5

[Nur InnoDB hat Zeilensperren; MyISAM, MEMORY und MERGE sind Tabellenebene] (http://dev.mysql.com/doc/refman/5.1/en/internal-locking.html) –

+1

Achten Sie darauf, andere Stackoverflow-Fragen zu Sperren auf Zeilenebene zu überprüfen Sicher, du machst eine gute Wahl. – belwood

Antwort

22

MySQL verwendet nur Sperren auf Tabellenebene von MyISAM -Tabellen. Wenn Sie können, wechseln Sie zum Sperren auf Zeilenebene zu InnoDB.

Hier ist ein Link zur MySQL-Seite, die Sperren beschreibt, die von SQL-Anweisungen für InnoDB-Tabellen gesetzt werden. http://dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html

+0

Funktioniert diese Sperre nur für diese Transaktion oder ist sie für die gesamte Datenbank dauerhaft? –

+0

Manchmal für die Transaktion, manchmal global. Sie sollten die Verriegelung sorgfältig lesen und verstehen, bevor Sie sie verwenden. Zum Beispiel gibt es verschiedene Arten von Sperren, wie "globale Lesesperre". Manchmal werden Sperren beim Commit automatisch freigegeben, andere werden möglicherweise zu Beginn einer Transaktion freigegeben. Ihre Anforderungen sollten bestimmen, welche Art von Sperren Sie verwenden sollten und wie Sie sie verwenden sollten. – belwood

1

Als Abhilfe können Sie eine Spalte auf den Tisch, wie locked TINYINT(1) hinzufügen - wenn Sie die Zeile Sie werden gesperrt setzen Sie ihn auf 1. Wenn Sie jetzt versuchen, auf diese Zeile zuzugreifen, überprüfen Sie zuerst, ob die Felder locked festgelegt sind.

Um die Zeile zu entsperren, setzen Sie sie einfach wieder auf 0. Nicht nett, aber ein wirklich einfacher Workaround.

+0

Wenn die Verbindung geschlossen ist, schließen Sie den Browser o.ä.Wenn es automatisch für andere freigeschaltet wird, denke ich, dass es nicht funktioniert.Amkorrekte ich? – svk

+0

Nein, natürlich wird es nicht. Sie könnten eine Art Job bereitstellen, der regelmäßig überprüft, ob für den Benutzer, der die Zeilensperre ausgelöst hat, eine Sitzung geöffnet ist. Natürlich müssen Sie dann einige Benutzerinformationen zur Tabelle hinzufügen. – dhh

+6

Aber das ist wie ein schlechter Semaphor, der die Rassenbedingungen nicht beseitigt. Wenn 2 gleichzeitige Abfragen "LOCK = 0" denken, dann gehen beide in den kritischen Abschnitt, _both_ set "LOCK = 1", und Sie haben einen versteckten Race Condition Bug. – bobobobo

-1

Eine bessere Problemumgehung besteht darin, eine Spalte zu erstellen, die einen Zeitstempel enthält. Wenn Sie die Zeile sperren möchten, aktualisieren Sie sie auf die aktuelle Zeit. So entsperren Sie das Update für mindestens x Minuten in der Vergangenheit. Um zu überprüfen, ob die Sperre aktiviert ist, überprüfen Sie, ob der Zeitstempel mindestens x Minuten alt ist.

Auf diese Weise läuft die Sperre effektiv ab, wenn der Prozess abstürzt (oder der Benutzer den Vorgang nie abschließt) nach x Minuten.

+2

Nicht gut - da das Prüfen und Aktualisieren keine einzige Operation ist, können zwei Verbindungen dieselbe Zeile sperren, ohne sich gegenseitig zu kennen. (Es gibt wahrscheinlich einen Weg, dies richtig zu machen, aber es wäre komplex und leicht zu vermasseln.) – Brilliand

+0

NIEMALS Timing als Ersatz für Sperren verwenden. –

2

Art spät, hofft aber es wird jemand helfen:

UPDATE user SET lastusedecnumber = LAST_INSERT_ID(lastusedecnumber + 1); 
SELECT LAST_INSERT_ID(); 

Werden Ihnen Atom Zuwachs von lastusedecnumber geben und die Fähigkeit, neuen Wert von lastusedecnumber Feld (nach Schritt) unter Verwendung von SELECT LAST_INSERT_ID() zu lesen.

+8

Es ist nicht klar, wie sich dies auf das Sperren einer Zeile bezieht ... – Brilliand

+0

Dies ist ein guter Vorschlag, da Sie die Zeile aktualisieren und den Wert lesen können (obwohl wie aktuell geschrieben, liest es den aktualisierten Wert und nicht den alten ein). Was es nicht erwähnt, ist, dass es, da es sich um ein Schreiben in die Tabelle handelt, die ganze Tabelle sperrt, während es die Zeile aktualisiert, wie es MyISAM tut - es kann nicht vermieden werden. – davidsheldon

0

Ich hatte keine Lust meine ganze Datenbank von myisam zu konvertieren. Also versuche ich einfach eine neue Tabelle zu erstellen, die auf der ID des Datensatzes basiert, den ich sperren möchte. Wenn create table erfolgreich ist, erledige meine Arbeit und lösche die Tabelle am Ende. Wenn create table nicht erfolgreich ist, stoppe.

Verwandte Themen