2009-06-18 9 views
5

Ammetto che non sono al 100% sul funzionamento interno di PDO e MySQL, quindi darò un esempio per chiarire la mia domanda.C'è un modo per forzare PHP ad aspettare fino a quando MySQL non ha finito con una transazione?

Sto facendo un gioco di strategia basato su browser piuttosto grezzo, perché penso che sia un modo divertente per imparare PHP e database. Stavo verificando i bug dello script di battaglia quando mi sono imbattuto in un bug piuttosto inatteso. Io uso Cron Jobs per chiamare uno script ogni minuto, cercando qualcosa del genere:

$ sql = "SELECT army_id FROM activearmy WHERE arrival = 0;";

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

     battleEngine($row["army_id"]); 

    } 

Quando i calcoli di base sono fatte (attacco esercito contro esercito in difesa), sei tabelle del database viene aggiornato. Il problema che devo affrontare è che quando eseguo diversi attacchi contro lo stesso bersaglio nello stesso minuto, ogni tanto uno di quegli attacchi recupera le informazioni obsolete del database (in un caso estremo, l'attacco n. 10 ha recuperato la stessa tabella dell'attacco n. 5). .

Immagino che questo accada perché lo script è più veloce del database? C'è un modo per forzare PHP ad aspettare fino a quando tutte le informazioni rilevanti sono a posto prima di ripetere la funzione con la riga $ successiva?

MODIFICA: Emil è probabilmente corretto. Non posso assicurarmi però perché sembra impossibile che il mio PDO rimanga aperto abbastanza a lungo da permettermi di passare diverse dichiarazioni tra beginTransaction() e commit(). Tuttavia, una lettura sporca sembra strana dato che sto usando InnoDB con "REPEATABLE READ". Alcuni googling suggeriscono che REPEATABLE READ renderà impossibili le letture sporche. Dopo aver pensato a come ammazzarmi per un po ', ho optato per un hack invece. Per ora, ho messo un UPDATE per un valore speciale in cima al mio script, e un altro alla fine del grande batch (circa sei istruzioni UPDATE) in basso. Prima di eseguire la funzione, ho messo su un while() - loop che controlla se quel valore speciale è impostato su 0. Se non lo è, dorme per 0,01 secondi e riprova. Osservando l'output, il ciclo while si ripete in media due volte, suggerendo che potrebbe effettivamente funzionare? Non ha ancora fallito, ma potrebbe essere perché non è l'ora di punta. Ci riproverò a intervalli regolari domani. So che nessuno si preoccupa di tutto questo, ma ho sentito che dovrei fare questo aggiornamento per ogni evenienza. = P

risposta

1

Se PHP dovesse semplicemente aspettare del tutto, si otterrebbe un numero elevato di lavori cron accatastati a.

Cosa si in realtà si desidera utilizzare qualcosa come anacron, per assicurarsi che solo una istanza dello script venga eseguita in un dato momento. Inoltre puoi fare qualcosa di simile al seguente:

<?php 

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

    // do your stuff 

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

srry per la formattazione errata – Evert

+1

Sarebbe meglio usare un blocco MySQL per questo, in questo modo se il lavoro e quindi la connessione muore, il blocco viene rilasciato automaticamente. http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock –

1

Quello che vedi è chiamato "lettura sporca". Utilizzare InnoDB e impostare isolation level su serializzabile. Poi avvolgere tutte le query di transazione-blocchi:

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