2012-04-14 33 views
29

Tengo una página de registro y básicamente necesito datos insertados en 4 tablas. Soy nuevo en PDO y estoy confundido por algo.PHP PDO Transacciones?

Básicamente, si falla alguna de las inserciones, no quiero agregar nada a la base de datos, eso parece bastante simple.

Mi confusión es que primero necesito insertar el nombre de usuario, correo electrónico, contraseña, etc. en mi tabla users para poder obtener (no estoy seguro) utilizando PDO que el uid MySQL le ha dado a mi usuario (auto incrementado por mysql). Necesito el usuario uid MySQL le dio a mi usuario las otras tablas, ya que las otras tablas necesitan el uid para que todo esté vinculado correctamente. Mis tablas son InnoDB y tengo claves externas que van desde users_profiles (user_uid), users_status (user_uid), users_roles (user_uid) hasta users.user_uid para que estén todos vinculados entre sí.

Pero al mismo tiempo quiero asegurarme de que si, por ejemplo, después de insertar datos en la tabla users (para que pueda obtener el usuario MySQL), si cualquiera de las otras inserciones falla, elimina los datos que se insertó en la tabla users.

Creo que es mejor que muestre mi código; He comentado el código y lo he explicado en el código, lo que puede facilitar su comprensión.

// Begin our transaction, we need to insert data into 4 tables: 
// users, users_status, users_roles, users_profiles 
// connect to database 
$dbh = sql_con(); 

// begin transaction 
$dbh->beginTransaction(); 

try { 

    // this query inserts data into the `users` table 
    $stmt = $dbh->prepare(' 
         INSERT INTO `users` 
         (users_status, user_login, user_pass, user_email, user_registered) 
         VALUES 
         (?, ?, ?, ?, NOW())'); 

    $stmt->bindParam(1, $userstatus,  PDO::PARAM_STR); 
    $stmt->bindParam(2, $username,  PDO::PARAM_STR); 
    $stmt->bindParam(3, $HashedPassword, PDO::PARAM_STR); 
    $stmt->bindParam(4, $email,   PDO::PARAM_STR); 
    $stmt->execute(); 

    // get user_uid from insert for use in other tables below 
    $lastInsertID = $dbh->lastInsertId(); 

    // this query inserts data into the `users_status` table 
    $stmt = $dbh->prepare(' 
         INSERT INTO `users_status` 
         (user_uid, user_activation_key) 
         VALUES 
         (?, ?)'); 

    $stmt->bindParam(1, $lastInsertID,  PDO::PARAM_STR); 
    $stmt->bindParam(2, $activationkey, PDO::PARAM_STR); 
    $stmt->execute(); 

    // this query inserts data into the `users_roles` table 
    $stmt = $dbh->prepare(' 
         INSERT INTO `users_roles` 
         (user_uid, user_role) 
         VALUES 
         (?, ?)'); 

    $stmt->bindParam(1, $lastInsertID,  PDO::PARAM_STR); 
    $stmt->bindParam(2, SUBSCRIBER_ROLE, PDO::PARAM_STR); 
    $stmt->execute(); 

    // this query inserts data into the `users_profiles` table 
    $stmt = $dbh->prepare(' 
         INSERT INTO `users_profiles` 
         (user_uid) 
         VALUES 
         (?)'); 

    $stmt->bindParam(1, $lastInsertID,  PDO::PARAM_STR); 
    $stmt->execute(); 

    // commit transaction 
    $dbh->commit(); 

} // any errors from the above database queries will be catched 
catch (PDOException $e) { 
    // roll back transaction 
    $dbh->rollback(); 
    // log any errors to file 
    ExceptionErrorHandler($e); 
    require_once($footer_inc); 
    exit; 
} 

Soy nuevo a la DOP y puede haber errores o problemas anteriormente todavía tengo que notar porque no puedo probar sin embargo, hasta que descubra mi problema.

1) Necesito saber cómo puedo insertar los datos de los usuarios en la tabla de usuarios en primer lugar para que pueda obtener el UID MySQL dio mi usuario

2) A continuación, obtener el UID que lo necesito para las otras tablas

3) Pero al mismo tiempo si una consulta falla por cualquier razón después de insertar en la tabla de usuarios que los datos también se eliminan de la tabla de usuarios también.

ACTUALIZACIÓN:

He actualizado el código de seguridad para reflejar los cambios que se ofrecen por los miembros de votos.

+3

a) Ponga '$ dbh-> beginTransaction();' y la línea anterior a eso fuera del bloque try/catch; no puede deshacer nada hasta que se inicie la transacción. b) ¿Qué no está funcionando con esto? Simplemente use lastInsertId como de costumbre. – Niko

+0

@Niko, haré esto en un momento, gracias phplover – PHPLOVER

+0

@Niko, edité el código anterior para reflejar el cambio que dijiste, ¿puedo preguntar por qué no puede el '$ dbh-> beginTransaction();' estar en el bloque de prueba también? no entiendo muy bien ese bit, gracias phplover – PHPLOVER

Respuesta

18

Esta función devuelve la clave principal del registro recién insertado: PDO::lastInsertId que lo necesitará para NEED_USERS_UID_FOR_HERE parámetro. Úselo justo después de la instrucción INSERT.

Desde que inició una transacción, los datos no se insertarán en ninguna tabla si se produce algún error siempre que use el motor InnoDB para sus tablas MySQL (MyISAM no admite transacciones).

+0

gracias, creo que lo estoy entendiendo ahora, puse '$ dbh-> lastInsertId();' después de la instrucción INSERT (vea el código editado en la publicación original), ahora recibí la última identificación de inserción haciendo lo que dijo anteriormente, cómo ¿ahora tengo acceso al último ID de inserción para ponerlo en las otras consultas 'NEED_USERS_UID_FOR_HERE'? lo siento, soy nuevo en PDO, así que todavía lo entiendo, gracias phplover – PHPLOVER

+0

lo siento, creo que podría explicarlo un poco mejor, simplemente asigno una variable a '$ dbh-> lastInsertId();' por lo que se convierte en algo así como '$ lastInsertID = $ dbh-> lastInsertId(); 'y luego ¿Dónde dice' NEED_USERS_UID_FOR_HERE' simplemente reemplace eso con '$ lastInsertID'? gracias phplover – PHPLOVER

+2

Sí. Simplemente almacénelo como una variable y úselo en otras consultas. No se escribirá en la base de datos si la transacción falla. –