Zurück   klamm-Forum > Virtual World > Programmierung

Antwort
 
LinkBack Themen-Optionen Ansicht
Alt 26.04.2011, 18:32:13   #1 (permalink)
Erfahrener Benutzer

ID: 171941
Lose-Remote

Reg: 25.04.2006
Beiträge: 1.916
Carny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer Anblick
Standard Race Conditions verhindern

Hallo,

ich entwickel gerade ein Script und habe folgendes Problem:

In einem Schritt möchte ich aus einer Datenbank einen bestimmten Eintrag auswählen. Jeder Eintrag hat einen Status (0...3) und der ausgewählte Eintrag soll den Status 0 haben. Direkt danach ändere ich in einem zweiten Schritt den Status auf 1.

Wie löse ich das am klügsten, ohne das während Schritt 1 und Schritt 2 eine Race Condition auftreten kann?

Meine SQL Statements sehen aktuell wie folgt aus:

Schritt 1:

Code:
1:
SELECT * FROM codes WHERE state='0' LIMIT 1,1
Schritt 2:

Code:
1:
UPDATE codes SET state='1' WHERE id=$id
Am besten wäre, beide Schritte in einen zu verschmelzen, also das ich den Status update und gleichzeitig die ID als Rückgabe selektiere. Ist dies möglich?

Gruß Carny
Carny ist offline   Mit Zitat antworten
Gesponsorte Links
Alt 26.04.2011, 18:35:06   #2 (permalink)
null != null
Benutzerbild von Sebmaster

ID: 238955
Lose-Remote

Sebmaster eine Nachricht über Skype™ schicken
Reg: 20.05.2006
Beiträge: 3.713
Sebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes Ansehen
Standard

Schau dir mal Transaktionen an
Kein Grafiker
Sebmaster ist offline   Mit Zitat antworten
Alt 26.04.2011, 18:35:55   #3 (permalink)
return void
Benutzerbild von ice-breaker

ID: 93995
Lose-Remote

ice-breaker eine Nachricht über ICQ schicken
Reg: 27.04.2006
Beiträge: 6.026
ice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehen
Standard

Transaktionen und SELECT ... LOCK IN EXCLUSIVE MODE

Edit: verdammt, da war einer schneller ^^ Aber Sebmaster, Transaktionen alleine verhindern den angesprochenen Sachverhalt nicht


"Die Wahrheit entgeht dem, der nicht mit beiden Augen sieht." -Orici
ice-breaker ist gerade online   Mit Zitat antworten
Alt 26.04.2011, 18:43:48   #4 (permalink)
Erfahrener Benutzer

ID: 171941
Lose-Remote

Reg: 25.04.2006
Beiträge: 1.916
Carny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer Anblick
Standard

Also sähe eine Beispiellösung so aus:

Code:
1:
2:
3:
4:
LOCK TABLES codes READ, codes WRITE SELECT * FROM codes WHERE state='0' LIMIT 1,1 UPDATE codes SET state='1' WHERE id=$id UNLOCK TABLES
Hab ich das richtig verstanden, das alle Anfragen auf eine bereits gesperrte Tabelle dann in eine Warteschlange kommen, anstatt das diese verloren gehen?

Gruß Carny
Carny ist offline Threadstarter   Mit Zitat antworten
Alt 26.04.2011, 19:01:28   #5 (permalink)
null != null
Benutzerbild von Sebmaster

ID: 238955
Lose-Remote

Sebmaster eine Nachricht über Skype™ schicken
Reg: 20.05.2006
Beiträge: 3.713
Sebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes Ansehen
Standard

Zitat:
Zitat von ice-breaker Beitrag anzeigen
Aber Sebmaster, Transaktionen alleine verhindern den angesprochenen Sachverhalt nicht
Könntest du das bitte noch genauer erklären?
Kein Grafiker
Sebmaster ist offline   Mit Zitat antworten
Alt 26.04.2011, 19:03:08   #6 (permalink)
alias Echnaton
Benutzerbild von transversalis

ID: 309239
Lose-Remote

Reg: 18.01.2008
Beiträge: 2.399
transversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehen
Standard

Würde denn ein

Code:
1:
SELECT * FROM codes WHERE state='0' LIMIT 1,1 FOR UPDATE;
nicht auch die gewünschte Sperre etablieren ?
"transversalis teleport" sprach der Magier und war fort
transversalis ist offline   Mit Zitat antworten
Alt 26.04.2011, 19:14:50   #7 (permalink)
return void
Benutzerbild von ice-breaker

ID: 93995
Lose-Remote

ice-breaker eine Nachricht über ICQ schicken
Reg: 27.04.2006
Beiträge: 6.026
ice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehen
Standard

Zitat:
Zitat von Carny Beitrag anzeigen
Hab ich das richtig verstanden, das alle Anfragen auf eine bereits gesperrte Tabelle dann in eine Warteschlange kommen, anstatt das diese verloren gehen?
ja, aber LOCK TABLES ist kein wirklich sinnvoller Ansatz, da du damit jeden Datensatz sperrst, mit Transaktionen würden nur die Datensätze gesperrt werden, die du auch nutzt, dementsprechend könnten die meisten anderen Querys ganz normal weiterarbeiten.

Zitat:
Zitat von Sebmaster Beitrag anzeigen
Könntest du das bitte noch genauer erklären?
Datenbanken wie MySQL verwenden MVCC, jede Transaktion sieht also einen konsistenten Snapshot der gesamten Datenbank der bei Beginn der Transaktion definiert wird.
Aus diesem Grunde ist kein Locking für Reads mehr nötig (im Gegensatz zu den definierten Isolation Levels von ANSI-SQL), ein Read wird also nie irgendwelche Daten locken, weder shared noch exklusiv.
Erst beim Schreiben von Daten werden Daten gelockt, das ist aber für das Beispiel von Carny schon zu spät.

Zitat:
Zitat von transversalis Beitrag anzeigen
Würde denn ein

Code:
1:
SELECT * FROM codes WHERE state='0' LIMIT 1,1 FOR UPDATE;
nicht auch die gewünschte Sperre etablieren ?
ja würde sie, ist auch die richtige Variante, meines war der Oracle-Befehl
SELECT ... FOR UPDATE und SELECT ... LOCK IN SHARE MODE, super Mysql, noch inkonsistenter kann man die Kommandos nicht bennen


"Die Wahrheit entgeht dem, der nicht mit beiden Augen sieht." -Orici
ice-breaker ist gerade online   Mit Zitat antworten
Alt 26.04.2011, 20:51:25   #8 (permalink)
Erfahrener Benutzer

ID: 171941
Lose-Remote

Reg: 25.04.2006
Beiträge: 1.916
Carny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer Anblick
Standard

Ok hab mir Select For Update jetzt mal genauer angeschaut. Wie bereits erwähnt ist mir das alles noch etwas unklar, aber ich versuch das mal etwas zu erklären.

Soweit ich das verstanden habe, wird bei diesem SQL Befehl eine Zeile aus der Datenbank bis zum nächsten Update gesperrt (für lesen oder schreiben gesperrt??). Was genau passiert jetzt, wenn eine andere Session genau die gleiche Zeile auswählt? Oder kann dies nicht passieren, wird dann wenn eine Zeile gesperrt ist diese bei Select-Anweisungen garnicht mehr beachtet, bis diese wieder entsperrt ist?

Aus den Fragen ergibt sich für mich auch, wie ich dies in Verbindung mit PHP behandeln muss, wenn zum Beispiel die zweite Session die gleiche Zeile auswählt. Kommt dann ein Fehler zurück und ich muss in einer Schleife arbeiten?

Geändert von theHacker (26.04.2011 um 20:52:28 Uhr) Grund: ...
Carny ist offline Threadstarter   Mit Zitat antworten
Alt 27.04.2011, 09:45:30   #9 (permalink)
alias Echnaton
Benutzerbild von transversalis

ID: 309239
Lose-Remote

Reg: 18.01.2008
Beiträge: 2.399
transversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehen
Standard

mit dem SELECT FOR UPDATE setzt Du einen exklusiven LOCK auf die row.
Andere sessions können diese Zeile dann weder lesen noch ändern ( im allgemeinen warten diese sessions dann, bis der Lock wieder aufgehoben ist, nur wenn das zu lange dauert kommt eine Fehlermeldung zurück "Timeout" ).

Der Lock, den Du damit etablierst, bleibt bis zum nächsten COMMIT bestehen.
Ein COMMIT kann explizit abgesetzt werden, oder implizit durch Beenden des Programms. Vorsicht, wenn Du autocommit verwendest, dann wird nach jedem statement ein automatischer commit abgesetzt und der Lock freigegeben.
"transversalis teleport" sprach der Magier und war fort
transversalis ist offline   Mit Zitat antworten
Alt 27.04.2011, 10:01:40   #10 (permalink)
Erfahrener Benutzer

ID: 171941
Lose-Remote

Reg: 25.04.2006
Beiträge: 1.916
Carny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer AnblickCarny ist ein wunderbarer Anblick
Standard

Super, vielen Dank für die ausführliche Erklärung.

Ich habe es gerade mal in Phpmyadmin versucht dies zu simulieren, indem ich auf eine Tabelle mit 2 Einträgen mehrmals SELECT ... FOR UPDATE aufgerufen habe. Ab dem 3. SELECT ... FOR UPDATE wurden allerdings immernoch Einträge ausgewählt, als wären die nicht gelocked worden. Oder benutzt Phpmyadmin dieses autocommit, das du angesprochen hattest?
Carny ist offline Threadstarter   Mit Zitat antworten
Alt 27.04.2011, 10:04:49   #11 (permalink)
null != null
Benutzerbild von Sebmaster

ID: 238955
Lose-Remote

Sebmaster eine Nachricht über Skype™ schicken
Reg: 20.05.2006
Beiträge: 3.713
Sebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes AnsehenSebmaster genießt hohes Ansehen
Standard

Wenn du die Querys immer getrennt absetzt, wird die Verbindung zu MySQL immer wieder getrennt => Locks aufgehoben.
Kein Grafiker
Sebmaster ist offline   Mit Zitat antworten
Alt 27.04.2011, 15:07:08   #12 (permalink)
return void
Benutzerbild von ice-breaker

ID: 93995
Lose-Remote

ice-breaker eine Nachricht über ICQ schicken
Reg: 27.04.2006
Beiträge: 6.026
ice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehen
Standard

Zitat:
Zitat von transversalis Beitrag anzeigen
mit dem SELECT FOR UPDATE setzt Du einen exklusiven LOCK auf die row.
aber auch nur für Querys, die ebenfalls die FOR UPDATE Erweiterung nutzen, alle anderen werden diesen Lock ignorieren.


"Die Wahrheit entgeht dem, der nicht mit beiden Augen sieht." -Orici
ice-breaker ist gerade online   Mit Zitat antworten
Alt 27.04.2011, 20:55:18   #13 (permalink)
alias Echnaton
Benutzerbild von transversalis

ID: 309239
Lose-Remote

Reg: 18.01.2008
Beiträge: 2.399
transversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehentransversalis genießt hohes Ansehen
Standard

Zitat:
Zitat von ice-breaker Beitrag anzeigen
aber auch nur für Querys, die ebenfalls die FOR UPDATE Erweiterung nutzen, alle anderen werden diesen Lock ignorieren.
warum das denn ?
Ein X-Lock ( exclusive-Lock ) sollte doch auch S-Locks ( Leselocks ) anderer threads verhindern, oder ?
"transversalis teleport" sprach der Magier und war fort
transversalis ist offline   Mit Zitat antworten
Alt 27.04.2011, 21:53:15   #14 (permalink)
return void
Benutzerbild von ice-breaker

ID: 93995
Lose-Remote

ice-breaker eine Nachricht über ICQ schicken
Reg: 27.04.2006
Beiträge: 6.026
ice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehenice-breaker genießt hohes Ansehen
Standard

neija durch den MVCC-Ansatz bzw. die mögliche Implementierung Snapshot Isolation [1] werden nie Leselocks gesetzt, von daher können Reads nicht mit den Schreiblocks unterbunden werden.
Generell ist da das Problem, dass der MVCC-Ansatz viele Grundlagen des ANSI-Isolationsmodells obsolet macht [2], da das Modell Transaktionen auf Basis von Locks beschreibt.

[1] http://en.wikipedia.org/wiki/Snapshot_isolation
[2] http://research.microsoft.com/pubs/69541/tr-95-51.pdf


"Die Wahrheit entgeht dem, der nicht mit beiden Augen sieht." -Orici
ice-breaker ist gerade online   Mit Zitat antworten
Alt 29.04.2011, 23:00:20   #15 (permalink)
Neuer Benutzer
Benutzerbild von chris_kay

Reg: 29.04.2011
Beiträge: 3
chris_kay wird schon bald berühmt werden
Standard

Um nochmal auf die Eingangsfrage zu kommen:
PHP-Code:
1:
2:
3:
4:
5:
mysqli::query("START TRANSMISSION");
mysqli::query("SELECT * FROM x WHERE y = z FOR UPDATE");
[
dazwischen]
mysqli::query("UPDATE x ... WHERE y = z");
mysqli::query("COMMIT"); 
... würde den gewünschten Effekt erzielen. [dazwischen] werden keine Änderungen an den entsprechenden Reihen vorgenommen. Andere PHP-Scripts [, die auf die selben Reihen zugreifen möchten] warten, bis die Transaktion beendet ist und laufen darauf hin normal weiter.
chris_kay ist offline   Mit Zitat antworten
Antwort

Gesponsorte Links

Anzeige


Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
 
Themen-Optionen
Ansicht

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks sind an
Pingbacks sind an
Refbacks sind an


Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Textmarkieren verhindern Slayer92 Programmierung 42 07.04.2009 13:16:18
[MySQL] Race Conditions chrissel Programmierung 24 12.05.2007 16:47:36
Spam verhindern eminion Multimedia & Kommunikation 16 21.02.2007 01:56:01
Rally Race CroBoy Lose4Scripts (erledigt) 28 15.01.2007 20:24:49


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:18:50 Uhr.