it-swarm.com.de

Wie kann ein Wert (Zähler) threadsicher abgefragt und erhöht werden? (Rennbedingungen vermeiden)

In einer Tabelle, in der jede Zeile einen Zähler hat (nur einen ganzzahligen Wert), muss ich den aktuellen Wert abrufen und ihn erhöhen gleichzeitig.

Eigentlich möchte ich das tun:

SELECT counter FROM table WHERE id=123
UPDATE table SET counter=counter+1 WHERE id=123

Dies als zwei Abfragen zu tun ist jedoch offensichtlich nicht threadsicher: Mehrere Prozesse, die dasselbe (in derselben Zeile) ausführen, erhalten möglicherweise denselben Zählerwert. Sie müssen alle eindeutig sein, damit jeder Prozess den aktuellen Wert aktuell erhält und um eins erhöht.

Ich kann mir eine Konstruktion vorstellen, bei der ich eine manuelle Sperre pro Zeile implementiere, aber ich frage mich, ob es einen einfacheren Weg gibt, dies zu tun.

10
RocketNuts

Die Update-Anweisungen funktionieren einwandfrei ohne die Auswahl zuvor! Da einzelne Anweisungen per Definition sicher sind, führt selbst zwei gleichzeitig ausgeführte UPDATE-Abfragen dazu, dass die Zeile zweimal erhöht wird.

Wenn Sie den Wert für Ihr Skript PHP) auswählen, etwas damit tun und später diesen genauen Zählerwert aktualisieren möchten, können Sie Folgendes tun:

BEGIN;
SELECT `counter` FROM `table` WHERE `id` = 123 FOR UPDATE;
UPDATE `table` SET `counter` = `counter`+1 WHERE `id` = 123;
COMMIT;

Dadurch wird eine neue Transaktion gestartet, dann werden die zu aktualisierenden Zeilen ausgewählt und ausschließlich gesperrt. Sie können diese dann sicher aktualisieren, ohne sich Sorgen machen zu müssen, dass andere Clients ihren Inhalt ändern oder sogar auf die gesperrten Zeilen zugreifen. Schließlich müssen Sie Ihre Änderungen festschreiben.

Sie sollten auch etwas über Isolationsstufen lesen. Sie möchten wahrscheinlich keinen Wert wie READ UNCOMMITTED als Isolationsstufe. Alles andere sollte für diesen Anwendungsfall in Ordnung sein.

15
GhostGambler