2011-12-23 24 views
5

Estoy tratando de configurar mi primera transacción en MySQL con PHP/DOP ...PHP MySQL DOP estructura del código de transacción

Sólo tengo una pregunta rápida, ¿cuál es la mejor manera de determinar si la consulta anterior fue exitoso o no? Esto es lo que tengo ahora, pero preferiría encontrar una manera de probar la consulta con una declaración if.

Esto es más o menos un código de simulacro para tratar de obtener un modelo funcional ... Sé que $ results no está probando efectivamente si algo era bueno o malo ... lo tengo más como un marcador de posición para el trato real cuando llegue el momento ..

if ($_POST['groupID'] && is_numeric($_POST['groupID'])) { 
    $sql = "SET AUTOCOMMIT=0"; 
    $dbs = $dbo->prepare($sql); 
    $dbs->execute(); 

    $sql = "START TRANSACTION"; 
    $dbs = $dbo->prepare($sql); 
    $dbs->execute(); 

    $sql = "DELETE FROM users_priveleges WHERE GroupID=:groupID"; 
    $dbs = $dbo->prepare($sql); 
    $dbs->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT); 
    $dbs->execute(); 

    try { 
     $sql = "DELETE FROM groups WHERE GroupID=:groupID LIMIT 1"; 
     $dbs = $dbo->prepare($sql); 
     $dbs->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT); 
     $dbs->execute(); 

     $results["error"] = null; 
     $results["success"] = true; 

     try { 
      $sql = "DELETE FROM users WHERE Group=:groupID"; 
      $dbs = $dbo->prepare($sql); 
      $dbs->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT); 
      $dbs->execute(); 

      $results["error"] = null; 
      $results["success"] = true; 

      $sql = "COMMIT"; 
      $dbs = $dbo->prepare($sql); 
      $dbs->execute(); 
     } 
     catch (PDOException $e) { 
      $sql = "ROLLBACK"; 
      $dbs = $dbo->prepare($sql); 
      $dbs->execute(); 

      $results["error"] = "Could not delete associated users! $e"; 
      $results["success"] = false; 
     } 
    } 
    catch (PDOException $e) 
    { 
     $sql = "ROLLBACK"; 
     $dbs = $dbo->prepare($sql); 
     $dbs->execute(); 

     $results["error"] = "COULD NOT REMOVE GROUP! $e"; 
     $results["success"] = false; 
    } 
} 
+2

Por qué no usar beginTransaction de DOP(), commit() y rollback() métodos? – GordonM

+0

LOL Acabo de enterarme del método startTransaction esta mañana ... Supuse que los otros dos estaban allí, pero aún no los había buscado. Eso está en la lista de TODO ¡gracias! – guyfromfl

+0

Además, no tiene que preparar() cada enunciado, de hecho es un desperdicio para aquellos en los que no va a insertar ninguna variable. Simplemente ejecute esos con query() en su lugar. Guarda en ambas líneas de código y se prepara innecesariamente. – GordonM

Respuesta

3

execute() retornos de DOP declaración verdadera en falso en caso de fracaso, para que pueda probar el valor de retorno de la anterior execute() en su sentencia if.

$pdo_result = $dbs->execute(); 
if ($pdo_result) { 
    // handle success 
} else { 
    // handle failure 
    // you can get error info with $dbs->errorInfo(); 
} 

Dicho esto, como @ Bill Kerwin señala correctamente (en su respuesta que estoy totalmente Upvoting porque es exactamente correcto), sería preferible utilizar PDO::beginTransaction(), PDO::commit() y PDO::rollback().

+0

¿Cómo sé cuál fue la causa del error? Me gustaría que sea receptivo al problema. Lo sentimos, la primera transacción todavía es nueva para PDO ... Gracias por la respuesta – guyfromfl

+1

'$ dbs-> errorInfo()' Consulte la documentación en http://www.php.net/manual/en/pdostatement.errorinfo.php para obtener una explicación de su valor de retorno. – Trott

+0

hermoso gracias ... – guyfromfl

6

No prepararía & para ejecutar las instrucciones de transacción. Usaría PDO::beginTransaction(), PDO::commit() y PDO::rollback().

PDO :: prepare() y PDO :: execute() devuelven FALSE si hay un error, o si no lanzan PDOException si setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION).

En su controlador de excepciones, debe marcar PDO::errorInfo() e informar la naturaleza del error. La mejor práctica es registrar la información de error sin procesar, pero darle al usuario un mensaje más amigable.

No repita el mensaje de error literal en la interfaz de usuario: esto puede dar al usuario un conocimiento inadecuado sobre su consulta SQL y su esquema.

+0

Sí, acabo de enterarme de los métodos de transacción anteriormente.Todo el motivo por el que quería controlarlo con declaraciones if es más fácil, para mí y mi experiencia limitada, detectar el error específico. También leí que los intentos no son ideales para lo que estoy haciendo por varias razones. Gracias por la info. mucho para mirar! – guyfromfl

+0

Acabo de comprobarlo dos veces, la opción setAttribute está establecida para ser aprobada cuando instancia el objeto $ dbo, así que estamos bien allí ... gracias por la retroalimentación – guyfromfl

20

Algunas notas generales: No utilice bindParam() a menos que utilice un procedimiento que modifica el valor del parámetro Por lo tanto, use bindValue(). bindParam() acepta el valor del argumento como una variable referenciada. Eso significa que no puede hacer $stmt->bindParam(':num', 1, PDO::PARAM_INT); - se produce un error. Además, PDO tiene sus propias funciones para controlar las transacciones, no necesita ejecutar consultas manualmente.

Reescribí su código un poco para arrojar algo de luz sobre cómo se puede utilizar DOP:

if($_POST['groupID'] && is_numeric($_POST['groupID'])) 
{ 
    // List the SQL strings that you want to use 
    $sql['privileges'] = "DELETE FROM users_priveleges WHERE GroupID=:groupID"; 
    $sql['groups']  = "DELETE FROM groups WHERE GroupID=:groupID"; // You don't need LIMIT 1, GroupID should be unique (primary) so it's controlled by the DB 
    $sql['users']  = "DELETE FROM users WHERE Group=:groupID"; 

    // Start the transaction. PDO turns autocommit mode off depending on the driver, you don't need to implicitly say you want it off 
    $pdo->beginTransaction(); 

    try 
    { 
     // Prepare the statements 
     foreach($sql as $stmt_name => &$sql_command) 
     { 
      $stmt[$stmt_name] = $pdo->prepare($sql_command); 
     } 

     // Delete the privileges 
     $stmt['privileges']->bindValue(':groupID', $_POST['groupID'], PDO::PARAM_INT); 
     $stmt['privileges']->execute(); 

     // Delete the group 
     $stmt['groups']->bindValue(":groupID", $_POST['groupID'], PDO::PARAM_INT); 
     $stmt['groups']->execute(); 

     // Delete the user 
     $stmt['users']->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT); 
     $stmt['users']->execute(); 

     $pdo->commit();  
    } 
    catch(PDOException $e) 
    { 
     $pdo->rollBack(); 

     // Report errors 
    }  
} 
+0

Wow gracias por la información bindParam/Value ... todos los tutoriales de PDO He leído que utilicé bindParam .. Ese código se ve muy bien, voy a jugar con sus ideas, tiene mucho sentido. – guyfromfl

+0

Recibo un error cuando intenta eliminar a los usuarios de ese grupo. El error dice cerca de Group = 38 ... Las otras dos consultas aún eliminan las otras filas en las otras tablas, parece que la transacción no funciona correctamente ... – guyfromfl

+0

'GROUP' es una palabra SQL reservada, por lo que puede que tenga que poner en citas posteriores. Pero sería mejor cambiarle el nombre, por lo que no es una palabra reservada, y también todas sus tablas lo llaman 'GroupID' consistentemente. –

Cuestiones relacionadas