04.-Transacciones
Las transacciones son un concepto fundamental de todos los sistemas de bases de datos. El punto esencial de una transacción es que agrupa múltiples pasos en una operación única, todo o nada. Los estados intermedios entre los pasos no son visibles para otras transacciones simultáneas, y si se produce algún fallo que impide que la transacción se complete, entonces ninguno de los pasos afecta a la base de datos en absoluto.
Por ejemplo, considere una base de datos bancaria que contenga saldos para diversas cuentas de clientes, así como saldos totales de depósitos para sucursales. Supongamos que queremos registrar un pago de $100.00 de la cuenta de Alice a la cuenta de Bob. Simplificando escandalosamente, los comandos SQL para esto podrían parecer:
UPDATE accounts SET balance = balance - 100.00
WHERE name = 'Alice';
UPDATE branches SET balance = balance - 100.00
WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Alice');
UPDATE accounts SET balance = balance + 100.00
WHERE name = 'Bob';
UPDATE branches SET balance = balance + 100.00
WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Bob');
Los detalles de estos comandos no son importantes aquí; el punto importante es que hay varias actualizaciones separadas involucradas para lograr esta operación bastante simple. Los oficiales de nuestro banco querrán estar seguros de que o todas estas actualizaciones ocurren, o ninguna de ellas sucede. Ciertamente no haría por un fallo del sistema que resultó en que Bob recibiera $100.00 que no fue debitado de Alice. Alice tampoco seguiría siendo una clienta feliz si fuera cargada sin que Bob fuera acreditado. Necesitamos una garantía de que si algo sale mal a lo largo de la operación, ninguno de los pasos ejecutados hasta ahora entrará en vigor. Agrupar las actualizaciones en una transacción nos da esta garantía. Se dice que una transacción es atómica: desde el punto de vista de otras transacciones, o bien ocurre completamente o no en absoluto.
También queremos una garantía de que una vez que una transacción sea completada y reconocida por el sistema de bases de datos, de hecho se haya registrado permanentemente y no se pierda incluso si se produce un accidente poco después. Por ejemplo, si estamos grabando un retiro de efectivo por parte de Bob, no queremos ninguna posibilidad de que el adeudo a su cuenta desaparezca en un accidente justo después de salir por la puerta del banco. Una base de datos transaccional garantiza que todas las actualizaciones realizadas por una transacción se registran en el almacenamiento permanente (es decir, en el disco) antes de que se informe de la transacción.
Otra propiedad importante de las bases de datos transaccionales está estrechamente relacionada con la noción de actualizaciones atómicas: cuando varias transacciones se ejecutan simultáneamente, cada una no debería ser capaz de ver los cambios incompletos realizados por otros. Por ejemplo, si una transacción está ocupada por un total de todos los saldos de la sucursal, no haría para que incluyera el adeudo de la sucursal de Alice, pero no el crédito a la sucursal de Bob, ni viceversa. Así que las transacciones deben ser todo o nada no sólo en términos de su efecto permanente en la base de datos, sino también en términos de su visibilidad a medida que suceden. Las actualizaciones realizadas hasta ahora por una transacción abierta son invisibles a otras transacciones hasta que la transacción se complete, con lo cual todas las actualizaciones se hacen visibles simultáneamente.
En PostgreSQL, una transacción se establece alrededor de los comandos SQL de la transacción con BEGIN
y COMMIT
comandos. Así que nuestra transacción bancaria en realidad se vería como:
BEGIN;
UPDATE accounts SET balance = balance - 100.00
WHERE name = 'Alice';
-- etc etc
COMMIT;
Si, a lo largo de la transacción, decidimos que no queremos comprometernos (quizás nos acabamos de notar que el saldo de Alice salió negativo), podemos emitir el comando ROLLBACK
en vez de COMMIT
, y todas nuestras actualizaciones hasta ahora serán canceladas.
PostgreSQL realmente trata cada declaración de SQL como si se ejecutara dentro de una transacción. Si no emites un BEGIN
comando, entonces cada declaración individual tiene un BEGIN
y (si tiene éxito) COMMIT
Envuelto alrededor de ella. Un grupo de declaraciones rodeados de BEGIN
y COMMIT
A veces se llama bloque de transacciones.
Nota Algunas bibliotecas clientes emiten
BEGIN
yCOMMIT
comandos automáticamente, para que pueda obtener el efecto de los bloques de transacciones sin preguntar. Coma control la documentación de la interfaz que está utilizando.
Es posible controlar las declaraciones en una transacción de una manera más granular a través del uso de puntos de ahorro. Savepoints le permite descartar selectivamente partes de la transacción, al tiempo que compromete el resto. Después de definir un punto de salvación con SAVEPOINT
, puede si es necesario volver al punto de salvado con ROLLBACK TO
. Todos los cambios de base de datos de la transacción entre definir el punto de reserva y volver a ella se descartan, pero los cambios antes del punto de salvado se mantienen.
Después de volver a un punto de salva, se sigue definiendo, por lo que puede volver a él varias veces. Por el contrario, si usted está seguro de que no tendrá que volver a un punto de salvado en particular de nuevo, se puede liberar, por lo que el sistema puede liberar algunos recursos. Tenga en cuenta que la liberación o la vuelta a un punto de ahorro liberará automáticamente todos los puntos de ahorro que se definieron después de él.
Todo esto está sucediendo dentro del bloque de transacciones, por lo que nada de esto es visible para otras sesiones de base de datos. Cuando y si usted comete el bloque de transacciones, las acciones comprometidas se hacen visibles como una unidad a otras sesiones, mientras que las acciones de la espalda enrollada nunca se hacen visibles en absoluto.
Recordando la base de datos del banco, supongamos que debitamos $100.00 de la cuenta de Alice, y la cuenta de acreditar a Bob, sólo para encontrar más tarde que deberíamos haber acreditado la cuenta de Wally. Podríamos hacerlo usando puntos de ahorro como este:
BEGIN;
UPDATE accounts SET balance = balance - 100.00
WHERE name = 'Alice';
SAVEPOINT my_savepoint;
UPDATE accounts SET balance = balance + 100.00
WHERE name = 'Bob';
-- oops ... forget that and use Wally's account
ROLLBACK TO my_savepoint;
UPDATE accounts SET balance = balance + 100.00
WHERE name = 'Wally';
COMMIT;
Este ejemplo es, por supuesto, demasiado simplificado, pero hay mucho control posible en un bloque de transacciones a través del uso de puntos de ahorro. Además, ROLLBACK TO
es la única manera de recuperar el control de un bloque de transacciones que fue puesto en estado abortado por el sistema debido a un error, a falta de rodarlo completamente y empezar de nuevo.