Seite 2 von 3

Verfasst: 04.02.2007 13:03
von gn#36
Naja bei meiner 2. Methode wird überhaupt kein Select benötigt, ich gehe davon aus, dass in die in mySql vorhandenen Vorkehrungen, einen doppelten Index zu verhindern ausreichen. Ich lasse von allen Skripten in die gleiche Tabelle den selben Wert im Index eintragen, da kann nur einer der schnellste sein, bei allen anderen schlägt der Insert Befehl fehl was sich am Rückgabewert der Funktion überprüfen lässt.
Sollte das nicht ausreichend sein würde das bedeuten, das mysql Tabellen nicht indexsicher sind, das kann ich mir ehrlich gesagt nicht vorstellen.

Verfasst: 04.02.2007 13:12
von mgutt
Mach bitte mal ein "Beispiel", wie Du das meinst.

Also eine Tabelle mit

gewinn_id user_id

Dann einen?

INSERT INTO tabelle (gewinn_id, user_id) VALUES ($gewinn_id, $user_id)

Du meinst sicher was anderes.

Gruß

Verfasst: 04.02.2007 13:17
von Emanuelle_1982
mgutt hat geschrieben:Ihr vergesst, dass es passieren kann (in der Millesekunde), dass nahezu synchron mehrere User den ersten SELECT ausführen können, bevor beim allerersten User der INSERT fertig ist.

D.h. es wird schon nach und nach abgearbeitet, aber in der Zeit zwischen den beiden Abfragen, kann es durchaus sein, dass noch ein SELECT eines anderen durchhuscht.

Ich hatte das bereits mehrmals in einem extrem frequenten Thema. Dort "beschwerten" sich User, dass ihr Beitrag erst auf Seite X und dann auf Seite Y angezeigt wurde. Weil dort ein weiterer User parallel geschrieben hat (INSERT) und dieser aber noch nicht vom SELECT erfasst werden konnte.
bei meiner Lösung nicht... (siehe unten beim edit)
ERST wird insert in 'soll-Seite-sehen' gemacht. erst DANACH wird in der GLEICHEN PHP datei nach der niedrigsten Tabellen ID gefragt.

Selbst wenn 2 user gleichzeitig drücken, wird nur einer die niedrige ID bekommen, darum kümmert sich mySQL

durch die Select Abfrage nach dem insert auf die gleiche Tabelle weisst du anschliessend wer als erster war (wie gesagt, die ID's werden von MySQL generiert - und nur einmal vergeben - das heisst es gibt immer eine niedrige ID, und NUR DIE hat gewonnen - alle anderen haben zwar den insert ausgeführt - aber eine höhere id und dürfen die Seite oder das Gewinsspiel NICHT sehen

also:
entscheidend ist bei mir nicht das insert, sondern das select von dem insert
das ist 100% sicher

von Sonderfällen wie Hacker angriff, mutwillige Änderung der Datenbank, Serverabstürze, etc abgesehen - aber ich glaube die darf man hier vernachlässigen

EDIT:
Bsp mit 2 Usern u1 und u2, Gewinnspiel g1

u1 findet Gewinnspiel
u2 findet Gewinnspiel

u1 trägt ein als 'soll-sehen'
(ID = 1 [mysql autoincrement], u1, g1)

u2 trägt ein als 'soll-sehen'
(ID = 2 [mysql autoincrement], u2, g1)

u1 macht select, Limit 1, orderBy ID wo gewinnspiel g1 auf 'sollen-sehen'
Eintrag: 1, u1, g1
hat gewonnen

u2 macht select, Limit 1, orderBy ID wo gewinnspiel g1 auf 'sollen-sehen'
Eintrag: 1, u1, g1
hat verloren, trotz insert !!

hiernach kann gewinnspiel g1 deaktivert werden damit nicht noch mehr inserts kommen
möglichkeit: trage als Gewinner - aber erst jetzt u1 ein

lösche hiernach alle einträge mit g1 aus der Tabelle 'soll-sehen'

Verfasst: 04.02.2007 13:25
von gn#36
Ok bleiben wir bei deinem Beispiel. Wichtig ist allerdings dass bei der Tabelle der Primärschlüssel auf gewinn_id liegt.
Außerdem muss die Variable $gewinn_id die du verwendest für alle Personen die an demselben Gewinnspiel teilnehmen gleich sein.
Wenn jetzt 2 Personen gleichzeitig versuchen ihre Id als Gewinner des Spiels einzutragen dann muss eine Person von beiden eine Fehlermeldung bekommen.
Um dein Beispiel noch mal zu vervollständigen:

Tabelle mit gewinn_id (PRIMARY), user_id

Dann einen

INSERT INTO tabelle (gewinn_id, user_id) VALUES (1, $user_id)

den alle versuchen auszuführen. Wenn Mysql richtig funktioniert sollte das - da auf gewinn_id ein Primärschlüssel liegt - nur bei einer einzigen Person funktionieren.
Das lässt sich natürlich dann erweitern, wenn man z.B. den 1. 2. und 3. Platz braucht, dann gibt es noch eine weitere Spalte, in der der Platz gespeichert wird, der dann ebenfalls zum Primärschlüssel hinzugehören muss (so dass die Kombination aus gewinn_id und rang immer eindeutig sein muss). Dann können alle User nacheinander alle Insertbefehle ausprobieren (bei Erfolg natürlich die anderen nicht mehr) also in etwa so:

Code: Alles auswählen

if(!mysql_query('INSERT INTO tabelle (gewinn_id, rang, user_id) VALUES (1,1, $user_id)'))
{
if(!mysql_query('INSERT INTO tabelle (gewinn_id, rang, user_id) VALUES (1,2, $user_id)'))
{
if(!mysql_query('INSERT INTO tabelle (gewinn_id, rang, user_id) VALUES (1,3, $user_id)'))
{
echo "Tja, da war jemand schneller...";
}
}
}

Verfasst: 04.02.2007 21:58
von Xwitz
gn#36 hat geschrieben:Warum sollte ein Server nicht mit mehreren Prozessen gleichzeitig auf eine Datenbank zugreifen? Genau das ist doch die Idee bei Mehrkernprozessoren, ...
An einen Mehrkernprozessor habe ich nicht gedacht der ist/sind aber im Grunde auch zwei Prozesoren. Auf eine Speicherzelle können Sie aber auch nicht gleichzeitig zugreifen. In die "Pause" zwischen dem select und dem nächten Zugriff könnte aber ein anderer Prozess reinhauen.
mgutt hat geschrieben:Ihr vergesst, dass es passieren kann (in der Millesekunde), dass nahezu synchron mehrere User den ersten SELECT ausführen können, bevor beim allerersten User der INSERT fertig ist.

D.h. es wird schon nach und nach abgearbeitet, aber in der Zeit zwischen den beiden Abfragen, kann es durchaus sein, dass noch ein SELECT eines anderen durchhuscht.
Das sagtest Du bereits. Sollen die Inserts doch ausgeführt werden, gewonnen hat der Erste in der Tabelle. Und sobald die ersten selects was ausspucken ist mit den Eintragungen schluß.

Verfasst: 04.02.2007 22:17
von Ambience
mein vorschlag..

erstelle tabelle gewinnspiel

mit den feldern: id(autoincrement), username

nun wenn man die seite aufruft, wird ein select befehl ausgeführt ob schon ein eintrag mit der id 1 drinne ist... wenn nicht wird der user eingetragen...

wenn ja, dann wird abgebrochen mit einer fehlermeldung: es tut uns leid aber ein anderes mitglied hat leider schon gewonnen...

oder hab ich da was falsch verstanden?

Verfasst: 04.02.2007 22:46
von Xwitz
Nö und wenn dennoch mehrere Einträge drin stehen, ist der Erste der Erste.

Verfasst: 05.02.2007 00:19
von mgutt
Also nach Xwitz Kommentare verstehe ich es so.. erst SELECT auf mögliche Gewinner, wenn nicht (das kann ruhig parallel durch mehrere passieren) ein INSERT. Danach wieder ein SELECT auf den niedrigsten autoincrement-Wert einer gewinnspiel_id. Und wenn dort die User_id mit der des Besuchers gleicht, dann sollte man es haben.

Also:
SELECT (nur true, wenn noch kein INSERT vorher war)
wenn true, dann INSERT
SELECT auf den Gewinner (true, wenn gewinner_id = user_id)

Auch praktikabel denke ich :D

Verfasst: 05.02.2007 00:49
von Jan500
mgutt hat geschrieben:Also:
SELECT (nur true, wenn noch kein INSERT vorher war)
wenn true, dann INSERT
SELECT auf den Gewinner (true, wenn gewinner_id = user_id)
du kannst auch nach dem ersten insert die id ausgeben mit $id = mysql_insert_id();

dann beim zweitem select prüfen ob die insert id mit der gefilterten (also dem ersten eintrag, am besten mit nem timestamp und dem niedrigsten auto_increment wert)) übereinstimmt so brauchst du nicht mit der user_id arbeiten...

Jan

Verfasst: 05.02.2007 04:28
von mgutt
Die user_id muss ich haben. Die brauche ich für die Gewinnerliste. Sonst weiß ich ja gar nicht wer gewonnen hat.

Gruß