2010-09-01 17 views
6

Tengo dos objetos PHP complicados, cada uno de los cuales tiene datos en algunas tablas de MySQL.¿Cómo puede averiguar un objeto PHP PDO si ya está en una transacción MySQL?

A veces, solo necesito eliminar un objeto A de la base de datos, y eso requiere 3 instrucciones SQL.

A veces, necesito eliminar un objeto B de la base de datos, que toma 4 instrucciones SQL, y también necesita encontrar y eliminar todos los objetos A que ese objeto B posee.

Entonces, dentro de la función delete_A(), ejecuto esas instrucciones dentro de una transacción. Dentro de la función que delete_B(), quiero ejecutar una gran transacción grande que cubra las actividades dentro de delete_A(). Si todo el átomo de eliminar un B falla, necesito restaurar todas sus A en la reversión.

¿Cómo actualizo la definición de delete_A() para abrir solo una nueva transacción si no hay una transacción más grande en ejecución.

que espera que sea capaz de hacer algo así, pero no parece que cambiarse por beginTransaction()

function delete_A($a){ 
    global $pdo; 
    $already_in_transaction = !$pdo->getAttribute(PDO::ATTR_AUTOCOMMIT); 
    if(!$already_in_transaction){ 
    $pdo->beginTransaction(); 
    } 

    //Delete the A 

    if(!$already_in_transaction){ 
    $pdo->commit(); 
    } 
} 
function delete_B($b){ 
    global $pdo; 
    $pdo->beginTransaction(); 
    foreach($list_of_As as $a){ 
    delete_A($a); 
    } 
    $pdo->commit(); 
} 
+0

Es posible que desee considerar el uso de restricciones de clave externa (significa que tendrá que cambiar de myISAM a un motor que las admita); de esta forma, puede hacer que el db haga eliminaciones en cascada en lugar de emularlas. – prodigitalson

Respuesta

2

Acabé usando la excepción lanzada por ->beginTransaction() de averiguar si estaba en una transacción, y utilizarlo para decidir si para comprometerse en el ciclo interno.Así delete_A() terminó pareciéndose a:

function delete_A($a){ 
    global $pdo; 
    try { 
    $pdo->beginTransaction(); 
    } catch (PDOException $e) { 
    $already_in_transaction = true; 
    } 

    //Delete the A 

    if(!$already_in_transaction){ 
    $pdo->commit(); 
    } 
} 

Y delete_B() obras sin modificación.

+0

¿Qué sucede si otra rutina que inició la transacción lo llama y decide retroceder? Su eliminación será deshecha. –

1

Una manera el atributo autocommit es crear su propia clase PDOConnect, que tiene una variable $hasTransaction . Entonces solo verifica eso. Se puede encontrar un ejemplo en los comentarios de la función beginTransaction en php.net aquí http://www.php.net/manual/en/pdo.begintransaction.php#81022

Esa sería mi preferencia. De acuerdo, ese ejemplo necesitará ajustar y vestirse, etc., pero debería ser una buena base para comenzar.

Nota al margen Recuerde que su tabla debe ser INNODB para que las transacciones funcionen. Y como necesita estar en INNODB para que las transacciones funcionen, debe tomar el consejo de prodigitalson y usar restricciones de clave externa.

7

PDO::ATTR_AUTOCOMMIT no es un atributo indicador, es un atributo de control. Controla si las sentencias SQL se comprometen implícitamente cuando finalizan.

Puede llamar PDO::inTransaction() que devuelve 0 si usted no tiene ninguna transacción en curso, y 1 si tiene una transacción pendiente que necesita ser confirmado o retrotraído. Sin embargo, esta función no está documentada, por lo que es difícil decir si es seguro depender de que esté presente en todas las versiones futuras de PDO.

Recomiendo que los desarrolladores de PHP no intenten administrar las transacciones dentro de la función o el alcance de clase. Debe administrar las transacciones en el nivel superior de la aplicación.

Consulte también:

+0

Gracias por los enlaces, eso me llevó a la solución que terminé usando. –

+2

inTransaction() ahora está documentado. http://php.net/manual/en/pdo.intransaction.php – morbidCode

+0

@morbidCode, gracias por la actualización! –

Cuestiones relacionadas