Wie verändert man einen Wert in einer Datenbank, ohne Gefahr da es ein anderer auch tut?
Frage etwas kompliziert gestellt, sorry. Es geht mir darum: wenn man einen Wert aus einer SQL Datenbank erst mit Select abruft und dann mit Update diesen + 1 wieder einfügt, das Fehler entstehen können wenn das 2 Leute gleichzeitig machen, oder? Wie kann man das verhindern?
MfG, Bohne47
2 Antworten
Ein "Select" ist kein Checkout, oder sowas. Gleichzeitige Änderungen sind nicht möglich, wenn es mal zu einer solchen Situation kommen würde, gibt es einen DB-Fehler a la "This record has been modified by another user"
An Sonsten sind 2 Änderungen hintereinander ( 2 Update Statements in 2 unterschiedlichen Sessions) kein Problem ( Gleichzeitigkeit gibt es spätestens bei Commits nicht mehr)
Ok, nichts anderes wollte ich beschreiben. Ich bin irgendwie davon ausgegangen, dass ein technischer Fehler verhindert werden soll.
Achso, jetzt habe ich, glaube ich, verstanden, was Du meinst. Ein Update ist eine atomare Operation. Der DB-Server führt solche Operationen normalerweise immer nacheinander aus, niemals gleichzeitig. Daher kommt es normalerweise nicht zu der Meldung, von der Du sprichst.
Ok, also: Wenn ich das soweit richtig verstanden habe: Es gibt, wenn 2 mal gleichzeitig ein Datensatz verändert wird, keine Fehlermeldung, sondern eines der beiden "gewinnt" und wird hingeschrieben. Das Problem ist halt: ich möchte einen Besucherzähler einbauen, der die Besucher die einen bestimmten Button geklickt haben in der Datenbank zählt (so ähnlich wie bei diesem was würdest du eher Game online wo man sieht wie viele Leute die Gleiche Antwort wie man selber gewählt haben.) Wie könnte man das beheben?
Also kommt dann ein Fehler und es wird abgebrochen oder versucht es der Computer erneut?
Dann müsstest Du eine Transaktion mit einem Isolation-Level oder Record Locking verwenden. Aber ja, das ist sogar oftmals ein Problem. Standardmäßig ist es eben nicht so, dass Datenbanken solche Fälle erkennen. Normalerweise gewinnt der, der zuletzt schreibt.
Beispiel:
Client A liest Datensatz A
Client B liest Datensatz A
Client B ändert im Datensatz das Feld "Name" auf Hallo
Client B macht ein Update auf Datensatz A
Client A ändert im Datensatz das Feld "Name" auf Welt
Client A macht ein Update auf Datensatz A
=> In der Datenbank steht im Datensatz A der Wert Welt.
Eine genaue Anleitung, wie man das verhindern kann, gibt es nicht. Im speziellen Fall solcher Increments, wie Du sie ansprichst, gibt es beispielsweise im SQL Server ein UPDATE ... OUTPUT Statement, das den Wert erhöht und den erhöhten Wert dann liefert. Anderenfalls müsste man eben das Update-Statement so schreiben, dass nicht der gelesene Wert + 1 verwendet wird, sondern der aktuelle Wert + 1 (z.B. für "Gelesen"-Zähler). Aber das hängt ganz von der Situation ab.
Wie lange braucht es denn wenn z.B. der Wert mit Select ausgelesen, dann um 1 erhöht wird und dann mit update eingefügt wird? Weil wenn das irgendwie 0.5 sekunden dauert ist mir das auch egal für einen besucherzähler, dann stimmt es halt nicht so ganz.
Musst Du mal messen. Das kann sehr unterschiedlich sein. Normalerweise sollte es schnell gehen.
Aber wie ZaoDaDong schon schreibt: Besucherlogs würde ich in Form einer Tabelle schreiben und nicht einfach als Zähler. Dann kannst Du den aktuellen Besucherstand mit einem einfach SELECT COUNT(*) ermitteln.
Das stimmt so nicht. Es ist in jedem mir bekannten Datenbanksystem sogar mit erhöhtem Aufwand verbunden, solche Isolationen zu programmieren. Normalerweise klappt das nur mit Transaktionen oder Record Locking.
Aber es ist immer ein Problem, wenn Client A und Client B denselben Datensatz abrufen und dann nacheinander Änderungen speichern. Standard ist eben, dass es hier KEINE Fehlermeldungen gibt, sondern dass das zuletzt geschriebene gewinnt.