Título: [solucionado] mysqli rollback todos los insert si uno falla
Publicado por: gAb1 en 10 Abril 2016, 03:31 am
Tengo un script que sube datos a diferentes tablas mysql y necesito que si un insert falla, no se haga ninguno. Para ello he estado leyendo y creo tener una idea clara: $mysqli = new mysqli(/* datos de conexión */); $mysqli->autocommit(FALSE); // el rollback lo dejará todo como estaba aquí $mysqli->begin_transaction(); if ($stmt_uno = $mysqli->prepare('INSERT INTO tabla_principal (uno, dos, tres) VALUES (?, ?, ?)')) { $stmt_uno->bind_param('sss', $uno, $dos, $tres); $stmt_uno->execute(); $id = (int) $mysqli->insert_id; if ($stmt_dos = $mysqli->prepare('INSERT INTO sub_tabla (principal_id, cuatro) VALUES (?, ?)')) { $stmt_dos->bind_param('is', $id, $cuatro); $stmt_dos->execute(); } if ($stmt_tres = $mysqli->prepare('INSERT INTO sub_tabla_dos (principal_id, cinco) VALUES (?, ?)')) { $stmt_tres->bind_param('is', $id, $cinco); $stmt_tres->execute(); } } if ($mysqli->commit()) { // todo correcto, se redirige } else { // algo ha salido mal, se llama rollback $mysqli->rollback(); // y se muestra un mensaje de error }
Todavía no lo he probado, pero no estoy seguro de si es así o hay que comprobar cada execute()... ¿Alguien puede corregirme? Gracias! Edito: cambio la estructura, el resto de inserts dependen del primero, pero si cualquiera falla no debe insertarse nada.
Título: Re: mysqli rollback todos los insert si uno falla
Publicado por: Gallu en 11 Abril 2016, 11:24 am
Hola, lo mejor en estos casos es usar bloques try catch. http://php.net/manual/es/language.exceptions.php De esta forma te aseguras de que ante cualquier error se ejecute el rollback Por ejemplo: $mysqli = new mysqli(/* datos de conexión */); $mysqli->autocommit(FALSE); // el rollback lo dejará todo como estaba aquí $mysqli->begin_transaction(); try{ if ($stmt_uno = $mysqli->prepare('INSERT INTO tabla_principal (uno, dos, tres) VALUES (?, ?, ?)')) { $stmt_uno->bind_param('sss', $uno, $dos, $tres); $stmt_uno->execute(); $id = (int) $mysqli->insert_id; if ($stmt_dos = $mysqli->prepare('INSERT INTO sub_tabla (principal_id, cuatro) VALUES (?, ?)')) { $stmt_dos->bind_param('is', $id, $cuatro); $stmt_dos->execute(); } if ($stmt_tres = $mysqli->prepare('INSERT INTO sub_tabla_dos (principal_id, cinco) VALUES (?, ?)')) { $stmt_tres->bind_param('is', $id, $cinco); $stmt_tres->execute(); } } if ($mysqli->commit()) { // todo correcto, se redirige } }catch(Exception $error){ //deshacemos todo $mysqli->rollback(); echo 'Excepción capturada: ', $error->getMessage(), "\n"; }
Título: Re: mysqli rollback todos los insert si uno falla
Publicado por: gAb1 en 12 Abril 2016, 02:35 am
Ah, al fin algo nuevo. Si que son muy utiles esos blockes. Gracias, dejo como lo he hecho: $mysqli = new mysqli(/* datos de conexión */); $mysqli->autocommit(FALSE); // el rollback lo dejará todo como estaba aquí $mysqli->begin_transaction(); try{ if ($stmt_uno = $mysqli->prepare('INSERT INTO tabla_principal (uno, dos, tres) VALUES (?, ?, ?)')) { $stmt_uno->bind_param('sss', $uno, $dos, $tres); if (!$stmt->execute()) { throw new Exception($stmt->error); } $id = (int) $mysqli->insert_id; if ($stmt_dos = $mysqli->prepare('INSERT INTO sub_tabla (principal_id, cuatro) VALUES (?, ?)')) { $stmt_dos->bind_param('is', $id, $cuatro); if (!$stmt->execute()) { throw new Exception($stmt->error); } } if ($stmt_tres = $mysqli->prepare('INSERT INTO sub_tabla_dos (principal_id, cinco) VALUES (?, ?)')) { $stmt_tres->bind_param('is', $id, $cinco); if (!$stmt->execute()) { throw new Exception($stmt->error); } } } if ($mysqli->commit()) { $redirect = TRUE; } else { throw new Exception('Transaction commit failed. Property ID: ' . $id); } } catch (Exception $e) { try { $mysqli->rollback(); $err_msg = $e->getMessage(); } catch (Exception $f) { $err_msg = $f->getMessage(); } } // es importante volver a activar el autocommit $mysqli->autocommit(TRUE);
Me costó un buen rato darme cuenta de por qué no se guardaba nada en la db :-\
|