2009-06-18 4 views
5

Ich gebe zu, ich bin nicht zu 100% auf das Innenleben von PDO und MySQL, also werde ich ein Beispiel geben, um meine Frage klarer zu machen.Gibt es eine Möglichkeit, PHP dazu zu zwingen, zu warten, bis MySQL mit einer Transaktion fertig ist?

Ich mache ein eher groben Browser-basierten Strategie-Spiel, weil ich es ist eine unterhaltsame Art und Weise denke, PHP und Datenbanken zu lernen. Ich habe das Battle Script getestet, als ich auf einen ziemlich unerwarteten Fehler stieß. Ich benutze Cron-Jobs, um jede Minute ein Skript aufzurufen, das etwa so aussieht:

$ sql = "SELECT armee_id VON activearmy WHERE arrival = 0;";

foreach($dbh->query($sql) as $row) 
    { 

     battleEngine($row["army_id"]); 

    } 

Wenn die grundlegenden Berechnungen durchgeführt (angreifende Armee Armee gegen die Verteidigung), sechs Tabellen in der Datenbank aktualisiert. Das Problem, dem ich gegenüberstehe, ist, dass wenn ich innerhalb derselben Minute mehrere Angriffe auf dasselbe Ziel mache, hin und wieder einer dieser Angriffe veraltete Datenbankinformationen holt (in einem Extremfall hat Angriff Nr. 10 dieselbe Tabelle wie Angriff Nr. 5 abgerufen) .

Ich vermute, dies geschieht, weil das Skript schneller als die Datenbank? Gibt es eine Möglichkeit, PHP zu zwingen, zu warten, bis alle relevanten Informationen vorhanden sind, bevor die Funktion mit der nächsten $ -Zeile wiederholt wird?

EDIT: Emil ist wahrscheinlich richtig. Ich kann jedoch nicht sicher gehen, da es für mein PDO unmöglich scheint, lange genug offen zu bleiben, um mehrere Anweisungen zwischen beginTransaction() und commit() zu übergeben. Ein Dirty-Read scheint jedoch seltsam, da ich InnoDB mit "REPEATABLE READ" verwende. Einige Googles deuten darauf hin, dass REPEATABLE READ schmutzige Lesevorgänge unmöglich machen wird. Nachdem ich überlegt hatte, wie ich mich für eine Weile töten könnte, entschied ich mich stattdessen für einen Hack. Im Moment habe ich ein UPDATE für einen speziellen Wert über mein Skript und ein weiteres am Ende des großen Stapels (etwa sechs UPDATE-Anweisungen) am unteren Rand platziert. Vor dem Ausführen der Funktion habe ich eine while() - Schleife erstellt, die überprüft, ob dieser spezielle Wert auf 0 gesetzt ist. Wenn dies nicht der Fall ist, wird sie für 0,01 Sekunden gespeichert und es wird erneut versucht. Wenn man sich die Ausgabe anschaut, wiederholt sich die while-Schleife durchschnittlich zweimal, was darauf hindeutet, dass sie tatsächlich funktioniert. Es ist noch nicht gescheitert, aber es könnte sein, dass es keine Hauptverkehrszeit ist. Ich werde es morgen in regelmäßigen Abständen wiederholen. Ich weiß, dass sich niemand für all das interessiert, aber ich hatte das Gefühl, ich sollte dieses Update nur für den Fall machen. = P

Antwort

1

Wenn PHP nur komplett warten würde, würden Sie eine hohe Anzahl von Cron-Jobs bekommen, die sich stapeln.

Was Sie wirklich wollen ist etwas wie Anachron zu verwenden, um sicherzustellen, dass nur eine Instanz des Skripts zu einem bestimmten Zeitpunkt ausgeführt wird. Sie könnte auch so etwas wie das folgende tun:

<?php 

    if (file_exists('/tmp/myscriptlock')) exit(); 
    touch('/tmp/myscriptlock'); 

    // do your stuff 

    unlink('/tmp/myscriptlock'); 
+0

srry für die schlechte Formatierung – Evert

+1

Es wäre besser, eine MySQL-Sperre dafür zu verwenden, auf diese Weise, wenn der Job und damit die Verbindung stirbt, dann wird die Sperre automatisch freigegeben. http://dev.mysql.com/doc/refman/5.0/en/miscellent-functions.html#function_get-lock –

1

Was Sie sehen eine „dirty read“ genannt wird. Verwenden Sie InnoDB, und legen Sie das isolation level Serializable fest. Dann wickeln Sie alle Abfragen in transaktions Blöcke:

$dbh->beginTransaction(); 
// run queries 
$dbh->commit();