Una vez realizada una conexión a través de PDO, es necesario comprender cómo PDO gestiona las transacciones antes de comenzar a realizar consultas. Si no se han manejado anteriormente transacciones, estas ofrecen cuatro características principales: Atomicidad, Consistencia, Aislamiento y Durabilidad (ACID por sus siglas en inglés). En términos sencillos, cualquier trabajo llevado a cabo en una transacción, incluso si se hace por etapas, se garantiza que será aplicado a la base de datos de forma segura, y sin interferencia de otras conexiones, cuando sea consignado ('commit'). El trabajo transaccional puede también ser deshecho automáticamente bajo petición (siempre y cuando no se haya consignado), lo que hace más sencillo el manejo de errores en los scripts.
Las transacciones son implementadas típicamente para hacer que el lote de cambios se apliquen a la vez; esto tiene el buen efecto secundario de mejorar 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 usarlas correctamente para obtener ese beneficio).
Desafortunadamente, no todas las bases de datos admiten transacciones, por lo que PDO necesita ser ejecutado en lo es conocido como el modo "auto-commit" cuando se abra por primera vez la conexión. El modo auto-commit significa que toda consulta que se ejecute tiene su propia transacción implícita, si la base de datos lo admite, o ninguna transacción si la base de datos no las admite. Si fuera necesario el uso de transacciones, se debe usar el método PDO::beginTransaction() para iniciar una. Si el controlador subyacente no admite transacciones, se lanzará una PDOException (independientemente de la configuración del manejo de errores: esto es siempre una condición de error serio). 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 comprueba las capacidades de la transacción al nivel del controlador. Si una
cierta condición en tiempo de ejecución implica que las transacciones no estén disponibles,
PDO::beginTransaction() seguirá devolviendo TRUE
sin ninún error si el servidor de bases de datos acepta la solicitud de iniciar una
transacción.
Un ejemplo de esto podría ser el 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 existe una transacción pendiente, PDO la revertirá automáticamente. Esto es una medida de seguridad que ayuda a evitar inconsistencia en los casos donde el script finaliza inesperadamente (si no consignó la transacción, se asume que algo salió mal, con lo cual se realiza la reversión para la seguridad de los datos).
La reversión automática sólo ocurre si se inicia una transacción a través de PDO::beginTransaction(). Si se ejecuta manualmente una consulta que inicie 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
En el siguiente ejemplo, se asume que se ha creado un conjunto de entradas para un nuevo empleado, al cual se le ha asignado el número de ID 23. Además de introducir los datos básicos de una persona, también es necesario registrar su sueldo. Es bastante simple hacer dos actualizaciones independientes, pero encerrándolas en las llamadas PDO::beginTransaction() y PDO::commit(), se garantiza que nadie más será capaz de ver los cambios hasta que se hayan 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 {
$gbd = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2',
array(PDO::ATTR_PERSISTENT => true));
echo "Conectado\n";
} catch (Exception $e) {
die("No se pudo conectar: " . $e->getMessage());
}
try {
$gbd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$gbd->beginTransaction();
$gbd->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
$gbd->exec("insert into salarychange (id, amount, changedate)
values (23, 50000, NOW())");
$gbd->commit();
} catch (Exception $e) {
$gbd->rollBack();
echo "Fallo: " . $e->getMessage();
}
?>
No hay límite en la realización de actualizaciones en una transacción; también es posible ejecutar consultas complejas para extraer datos, y posiblemente usar esa 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 más información sobre transacciones, consulte la documentación proporcionada por su servidor de base de datos.