2010-12-05 7 views
26

Ich mache eine Website, wo ich einen Zähler in einer Standard-MyISAM-Tabelle erhöhen möchte.Erhöht ein Feld in MySQL atomar?

Vereinfachtes Beispiel:

UPDATE votes SET num = num + 1; 

wird dies zu Problemen führen, wenn mehrere Verbindungen die gleiche Abfrage zu tun, oder wird MySQL darum kümmern und verriegeln Sie die Tabelle oder etwas, um sicherzustellen, dass es keine Konflikte?

+0

Sie könnten auch in meiner Antwort auf eine andere Sperr Frage interessieren: http://stackoverflow.com/questions/3312361/does-this-lock -the-database/3312790 # 3312790 – Mike

Antwort

12

MyISAM-Tabellen verwenden Sperren auf Tabellenebene. Dies bedeutet, dass die gesamte Tabelle während der Ausführung Ihrer Aktualisierungsabfrage gesperrt wird. Die Antwort für Ihren vereinfachten Anwendungsfall lautet also: Ja, das ist Thread-sicher. Dies ist jedoch möglicherweise nicht der Fall, wenn Sie eine andere Speicher-Engine verwenden oder Ihr Update mehrere Tabellen enthält. Hier

ist ein Zitat aus dem MySQL-Handbuch für mehr Klarheit:

Tabellensperren ermöglicht viele Sitzungen aus einer Tabelle lesen zur gleichen Zeit, aber wenn eine Sitzung will eine Tabelle schreiben , es muss zuerst exklusive Zugriff erhalten. Während des Updates müssen alle anderen -Sitzungen, die auf diese spezielle Tabelle zugreifen möchten, warten, bis das Update abgeschlossen ist.

Sie können auch die Verwendung von Autoinkrement-Spalten, Transaktionen oder externer Synchronisation in Erwägung ziehen, wenn dies zu Ihrem Design passt.

Prost!

3

Diese Form von UPDATE ist atomar. Andere Formen von UPDATE können durch Verwendung von Transaktionen mit atomar gemacht werden.

4

Ja, die Tabelle (oder Zeilen in Datenbanken im InnoDB-Format) wird automatisch gesperrt, wenn Sie eine Aktualisierungsabfrage ausführen.

18

Der Schreibvorgang ist atomar, aber ein Inkrement erfordert auch einen Lesevorgang. Die Frage ist also: Sind Sie sicher, dass das Lesen sicher ist, mit anderen Worten, sind Sie sicher, dass ein anderer Thread, der das Inkrement durchführt, nicht mit dem gleichen Wert inkrementiert wird? Ich habe Zweifel. Die 100% richtige Vorgehensweise wäre dies.

-- begin transaction here 

select counter from myCounters where counter_id = 1 FOR UPDATE; 

-- now the row is locked and nobody can read or modify its values 

update myCounters set counter = ? where id = 1; 

-- set ? to counter + 1 programmatically 

commit; -- and unlock... 
+1

Ich bin ziemlich sicher, dass das OPs-Beispiel von UPDATE SET field = field + 1 keine Nebenläufigkeitsprobleme verursacht, aber dies ist der beste Weg, um sicherzustellen, dass Sie die Zeile/Tabelle beim Modifizieren sperren ein Feld. In der Regel macht es mehr Sinn, wenn Sie eine komplexere Operation durchführen. – Nicholi

0

hatte das gleiche Problem, obwohl Abfrage komplizierter war:

UPDATE CLB_SYNC_T SET PENDING_MESSAGES = PENDING_MESSAGES + ? WHERE USER_ID = ? 

Mit MyISAM als Standard-Engine hat nicht geholfen, so dass ich Rückgriff auf SELECT FOR UPDATE Verwendung.

Mit SELECT FÜR UPDATE Performance verbessert ~ 10 mal, da MySQL nicht ganze Tabelle gesperrt, um eine Zeile zu aktualisieren.

0

Ein weiterer Ansatz, wenn InnoDB verwendet, wird mit eindeutigen Index auf mehrere Spalte wie folgt:

Table 'Sessions' { unique_key (browser_session_id, profile_id) // stellt sicher, dass pro Sitzung 1 Eintrag Einfügen einmal auftreten }

select count (browser_session_id) von Sessions

r garantieren, Folge eindeutiger Sitzungen, da mehrere Sitzungen pro Benutzer nicht zulässig sind.

Schlussfolgerungen

  • Vorteil

    Jeder Einsatz eine Vorauswahl erfordert.

  • Nachteil

    Es ist für alle Fälle nicht geeignet.

    Kann Schreibleistung verlangsamen, und erfordert zusätzliche Management