2009-06-18 10 views
5

Admitiré que no estoy al 100% en el funcionamiento interno de PDO y MySQL, así que daré un ejemplo para aclarar mi pregunta.¿Hay alguna manera de forzar a PHP a esperar hasta que MySQL haya terminado con una transacción?

Estoy haciendo un juego de estrategia basado en el navegador bastante crudo, porque creo que es una forma divertida de aprender PHP y bases de datos. Estuve probando errores en el script de batalla cuando me encontré con un error bastante inesperado. Uso Cron Jobs para llamar a un script cada minuto, con un aspecto similar al siguiente:

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

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

     battleEngine($row["army_id"]); 

    } 

Cuando los cálculos básicos se hacen (atacar ejército frente a la defensa del ejército), seis tablas en la base de datos se actualiza. El problema que enfrento es que cuando realizo varios ataques contra el mismo objetivo en el mismo minuto, de vez en cuando uno de esos ataques obtiene información obsoleta de la base de datos (en un caso extremo, el ataque # 10 fue a la misma mesa que el ataque # 5) .

Supongo que esto sucede porque el script es más rápido que la base de datos? ¿Hay alguna manera de obligar a PHP a esperar hasta que toda la información relevante esté en su lugar antes de repetir la función con la próxima $ row?

EDITAR: Emil probablemente sea correcto. Sin embargo, no puedo asegurarlo, ya que parece imposible que mi PDO permanezca abierta el tiempo suficiente para que pase varias declaraciones entre beginTransaction() y commit(). Sin embargo, una lectura sucia parece extraña ya que estoy usando InnoDB con "REPEATABLE READ". Algunos de Google sugieren que LECTURA REPETIBLE hará que las lecturas sucias sean imposibles. Después de contemplar cómo suicidarme por un tiempo, opté por un hack en su lugar. Por ahora, puse una ACTUALIZACIÓN para un valor especial en la parte superior de mi secuencia de comandos, y otra al final del gran lote (alrededor de seis instrucciones de ACTUALIZACIÓN) en la parte inferior. Antes de ejecutar la función, coloqué un while() - loop que comprueba si ese valor especial está establecido en 0. Si no es así, duerme durante 0.01 segundos y vuelve a intentarlo. Al mirar la salida, el ciclo while repite un promedio de dos veces, sugiriendo que en realidad podría estar funcionando. Todavía no ha fallado, pero podría ser porque no es la hora pico. Lo intentaré nuevamente a intervalos regulares mañana. Sé que a nadie le importa todo esto, pero sentí que debería hacer esta actualización por si acaso. = P

Respuesta

1

Si PHP simplemente esperara por completo, obtendría un gran número de trabajos de cron acumulando.

Lo que realmente quiere es usar algo como anachron, para asegurarse de que solo se ejecute una instancia del script en un momento dado. También podría hacer algo como lo siguiente:

<?php 

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

    // do your stuff 

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

srry para el mal formato – Evert

+1

Sería mejor utilizar un bloqueo de MySQL para esto, de esa manera si el trabajo y la conexión mueren, entonces el bloqueo se libera automáticamente. http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get -lock –

1

Lo que está viendo se denomina "lectura sucia". Use InnoDB y configure el isolation level como serializable. Luego envuelva todas las consultas en las transacciones bloques:

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