Una vez conectado a través de PDO, es necesario comprender cómo PDO gestiona las transacciones antes de que se comience a ejecutar consultas. Si no se ha manejado anteriormente transacciones, ofrecen 4 principales características: Atomicidad, Consistencia, Aislamiento y Durabilidad (siglas ACID, en inglés). En términos sencillos, cualquier trabajo llevado a cabo en una transacción, incluso si se lleva a cabo por etapas, se garantiza que serán aplicado en la base de datos de forma segura, y sin interferencia de otras conexiones, cuando se realice un "commit". El trabajo transaccional puede también ser deshecho automáticamente bajo petición (siempre y cuando no se haya realizado un "commit"), lo que hace el manejo de errores en los scripts más fácil.
Las transacciones son implementadas típicamente para ahorrar el lote de cambios que se aplicarán a la vez; esto tiene un buen efecto secundario que mejora drásticamente la eficiencia de las actualizaciones. En otras palabras, las transacciones pueden hacer los scripts más rápidos y potencialmente más robustos (aún así es necesario usarlos correctamente para obtener ese beneficio).
Desafortunadamente, no todas las bases de datos soportan transacciones, con lo cual PDO necesita ejecutar lo que es conocido como el modo "auto-commit" cuando se abra por primera vez la conexión. El modo auto-commit implica que toda consulta que se ejecute tiene su propia transacción implícita, si la base de datos lo soporta, o ninguna transacción si la base de datos no las soporta. Si se necesitan transacciones, se debe usar el método PDO::beginTransaction() para iniciar una. Si el driver subyacente no soporta transacciones, se lanzará una PDOException (independientemente de las preferencias del manejo de errores: esto es una condición de error serio siempre). Una vez que se esté en una transacción, se puede usar PDO::commit() o PDO::rollBack() para finalizarla, dependiendo del éxito del código que se ejecute durante la transacción.
PDO sólo compruebas las capacidades de la transacción a nivel de driver. Si una
cierta condición en tiempo de ejecución significa que las transacciones no están disponibles,
PDO::beginTransaction() seguirá devolviendo TRUE
sin error si el servidor de base de datos acepta la solicitud de iniciar una
transacción.
Un ejemplo de esto puede ser intentar usar transacciones en tablas MyISAM en una base de datos MySQL.
Cuando el script finaliza o cuando una conexión está a punto de ser cerrada, si se tiene una transacción pendiente, PDO la deshará automáticamente. Esto es una medida de seguridad que ayuda a evitar inconsistencia en los casos donde el script finaliza inesperadamente--si no se ha realizado explícitamente un "commit" de la transacción, se asuma que algo salió mal, con lo cual se vuelve al estado anterior para la seguridad de los datos.
La vuelta automática al estado anterior sólo ocurre si se inicia una transacción a través de PDO::beginTransaction(). Si se ejecuta manualmente una consulta que inicia una transacción, PDO no tiene forma de conocer algo acerca de ésta y por tanto no puede revertirla si algo sale mal.
Ejemplo #1 Ejecución de un lote en una transacción
Para el siguiente ejemplo, se asume que se crea un conjunto de entradas para un nuevo empleado, al cual se le ha asignado un ID de 23. Además de introducir los datos básicos de una persona, también es necesario almacenar su sueldo. Es bastante simple hacer dos actualizaciones independientes, pero envolviéndolas en las llamadas PDO::beginTransaction() y PDO::commit(), estamos garantizando que nadie más será capaz de ver los cambios hasta que se haya completado. Si algo sale mal, el bloque catch revierte los cambios realizados desde que se creó la transacción, y luego imprime un mensaje de error.
<?php
try {
$dbh = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2',
array(PDO::ATTR_PERSISTENT => true));
echo "Connected\n";
} catch (Exception $e) {
die("Unable to connect: " . $e->getMessage());
}
try {
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->beginTransaction();
$dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
$dbh->exec("insert into salarychange (id, amount, changedate)
values (23, 50000, NOW())");
$dbh->commit();
} catch (Exception $e) {
$dbh->rollBack();
echo "Failed: " . $e->getMessage();
}
?>
No se está limitado a la realización de actualizaciones en una transacción; también es posible ejecutar consultas complejas para extraer datos, y posiblemente usar usa información para construir más actualizaciones y consultas; mientras que la transacción esté activa se garantiza que nadie más puede realizar cambios mientras se esté en mitad del trabajo. Para leer más sobre transacciones, consulte la documentación proporcionada por su servidor de base de datos.