TRANSACCIONES.doc

10
Transacciones Las transacciones son un concepto fundamental de todos los sistemas de bases de datos. El punto esencial de una transacción es su capacidad para empaquetar varios pasos en una sola operación “todo o nada”. Los estados intermedios entre los pasos no son visibles para otras transacciones concurrentes, y si ocurre alguna falla que impida que se complete la transacción, entonces ninguno de los pasos se ejecuta y no se afecta la base de datos en absoluto. EJEMPLO 1 Trabajaremos con la base de datos Northwind en nuestros ejemplos. Vamos a realizar una transacción que modifica el precio de dos productos de la base de datos. USE NorthWind DECLARE @Error int --Declaramos una variable que utilizaremos para almacenar un posible código de error BEGIN TRAN --Iniciamos la transacción

Transcript of TRANSACCIONES.doc

Transacciones

Las transacciones son un concepto fundamental de todos los sistemas de bases de datos. El punto esencial de una transaccin es su capacidad para empaquetar varios pasos en una sola operacin todo o nada. Los estados intermedios entre los pasos no son visibles para otras transacciones concurrentes, y si ocurre alguna falla que impida que se complete la transaccin, entonces ninguno de los pasos se ejecuta y no se afecta la base de datos en absoluto.

EJEMPLO 1Trabajaremos con la base de datos Northwind en nuestros ejemplos.

Vamos a realizar una transaccin que modifica el precio de dos productos de la base de datos.

USE NorthWind

DECLARE @Error int

--Declaramos una variable que utilizaremos para almacenar un posible cdigo de error

BEGIN TRAN

--Iniciamos la transaccin

UPDATE Products SET UnitPrice=50 WHERE ProductName =Chai

--Ejecutamos la primera sentencia

SET @Error=@@ERROR

--Si ocurre un error almacenamos su cdigo en @Error

--y saltamos al trozo de cdigo que deshar la transaccin. S, eso de ah es un

--GOTO, el demonio de los programadores, pero no pasa nada por usarlo

--cuando es necesario

IF (@Error0) GOTO TratarError

--Si la primera sentencia se ejecuta con xito, pasamos a la segunda

UPDATE Products SET UnitPrice=50 WHERE ProductName=Chang

SET @Error=@@ERROR

--Y si hay un error hacemos como antes

IF (@Error0) GOTO TratarError

--Si llegamos hasta aqu es que los dos UPDATE se han completado con

--xito y podemos "guardar" la transaccin en la base de datos

COMMIT TRAN

TratarError:

--Si ha ocurrido algn error llegamos hasta aqu

If @@Error0 THEN

BEGIN

PRINT Ha ecorrido un error. Abortamos la transaccin

--Se lo comunicamos al usuario y deshacemos la transaccin

--todo volver a estar como si nada hubiera ocurrido

ROLLBACK TRAN

END

Como se puede ver para cada sentencia que se ejecuta miramos si se ha producido o no un error, y si detectamos un error ejecutamos el bloque de cdigo que deshace la transaccin.

Hay una interpretacin incorrecta en cuanto al funcionamiento de las transacciones que esta bastante extendida. Mucha gente cree que si tenemos varias sentencias dentro de una transaccin y una de ellas falla, la transaccin se aborta en su totalidad.

Nada ms lejos de la realidad!

Si tenemos dos sentencias dentro de una transaccin.

USE NorthWind

BEGIN TRAN

UPDATE Products SET UnitPrice=50 WHERE ProductName=Chang

UPDATE Products SET UnitPrice=50 WHERE ProductName=Chang

COMMIT TRAN

Estas dos sentencias se ejecutarn como una sola. Si por ejemplo en medio de la transaccin (despus del primer update y antes del segundo) hay un corte de electricidad, cuando el SQL Server se recupere se encontrar en medio de una transaccin y, o bien la termina o bien la deshace, pero no se quedar a medias.

El error est en pensar que si la ejecucin de la primera sentencia da un error se cancelar la transaccin. El SQL Server slo se preocupa de ejecutar las sentencias, no de averiguar si lo hacen correctamente o si la lgica de la transaccin es correcta. Eso es cosa nuestra.

Por eso en el ejemplo que tenemos ms arriba para cada sentencia de nuestro conjunto averiguamos si se ha producido un error y si es as actuamos en consecuencia cancelando toda la operacin.

EJEMPLO 2Considere una base de datos bancaria que contiene balances de varias cuentas de clientes y balances totales de depsito de sucursales. Suponga que queremos registrar un pago de $100 de la cuenta de Alicia a la de Roberto. Simplificando la operacin exageradamente, las rdenes SQL para hacerlo se veran as:UPDATE cuentas SET balance = balance - 160.00 WHERE nombre = 'Alicia';

UPDATE sucursales SET balance = balance - 160.00 WHERE nombre = (SELECT sucursal FROM cuentas WHERE nombre = 'Alicia');

UPDATE cuentas SET balance = balance + 160.00 WHERE nombre = 'Roberto';

UPDATE sucursales SET balance = balance + 160.00 WHERE nombre = (SELECT sucursal FROM cuentas WHERE nombre = 'Roberto');

Los detalles de estas rdenes no son importantes en este momento; lo que importa es que hay varias actualizaciones separadas involucradas para lograr esta operacin ms o menos sencilla. Los operadores bancarios van a querer estar seguros de que o todos estos pasos se ejecutan o no se ejecuta ninguno. Definitivamente no sera aceptable si una falla del sistema resulta en que Roberto recibe $100 que no fueron debitados de la cuenta de Alicia. Tampoco si a Alicia le debitaran y a Roberto no le abonaran. Se necesita una garanta de que si algo sale mal en el transcurso de la operacin, ninguno de los pasos ejecutados hasta el momento tendrn efecto. Para el ejemplo anterior, agrupar las actualizaciones en una transaccin proporciona esa garanta. De las transacciones se dice que son atmicas: desde el punto de vista de otras transacciones, la transaccin ocurre completamente o no ocurre en absoluto.

Tambin es necesario garantizar que, despus que se complete una transaccin y que el sistema de bases de datos tenga completo conocimiento de ella, realmente el registro haya sido permanente y que este no se perder, incluso si llega a suceder una falla poco tiempo despus. Por ejemplo, si se estuviera registrando un retiro de Roberto, no sera aceptable que el dbito de su cuenta desapareciera en una falla del sistema justo despus de que l sale del banco. Una base de datos transaccional garantiza que todas las actualizaciones realizadas por una transaccin se grabarn en un medio de almacenamiento permanente (en disco, por ejemplo) antes de que la transaccin se reporte completamente.

Otra propiedad importante de las bases de datos transaccionales se relaciona con la nocin de las actualizaciones atmicas: cuando hay muchas transacciones concurrentes, ninguna de ellas debera conocer los cambios incompletos hechos por las dems. Por ejemplo, si alguna transaccin est ocupada totalizando todos los balances de una sucursal, no servira que incluyera el dbito de la sucursal de Alicia pero no el crdito a la sucursal de Roberto, ni viceversa. As que las transacciones deben ser todo o nada, no solamente en trminos de su efecto permanente en la base de datos, sino tambin en trminos de su visibilidad a medida que suceden. Las actualizaciones hechas hasta cierto momento por una transaccin abierta son invisibles para las dems transacciones hasta que la transaccin se complete. A partir de su finalizacin, todas las actualizaciones se hacen visibles simultneamente.

En PostgreSQL, una transaccin se indica encerrando las rdenes SQL de la transaccin entre las rdenes BEGIN y COMMIT. Entonces la transaccin bancaria del ejemplo de arriba se vera as:

BEGIN;UPDATE cuentas SET balance = balance - 160.00 WHERE nombre = 'Alicia';-- etc etcCOMMIT;Si en medio de una transaccin se decide que ya no se quiere registrar los cambios (tal vez el balance de Alicia se volvi negativo en algn momento, por ejemplo), se puede recurrir a la orden ROLLBACK en lugar de COMMIT y todas las actualizaciones hasta ese punto quedaran canceladas.

De hecho, PostgreSQL trata cada declaracin de SQL como si se estuviera ejecutando dentro de una transaccin. Si uno no especifica una orden BEGIN, entonces cada declaracin individual tiene un BEGIN y, si es exitosa, un COMMIT alrededor de ella. Algunas veces, a un grupo de declaraciones encerradas entre BEGIN y COMMIT se les llama un bloque de transaccin.

Es posible controlar las declaraciones en una transaccin de una manera ms granular por medio de puntos de recuperacin (savepoints). Los puntos de recuperacin permiten descartar selectivamente algunas partes de la transaccin mientras las dems s se ejecutan. Despus de definir un punto de recuperacin con SAVEPOINT, se puede volver a l si es necesario por medio de ROLLBACK TO. Todos los cambios de la base de datos hechos por la transaccin entre el punto de recuperacin y el rollback se descartan, pero los cambios hechos antes del punto de recuperacin se mantienen.

Despus de volver a un punto de recuperacin, este ltimo sigue definido, o sea que se puede volver a l varias veces. Y al contrario, si uno est seguro de que no necesita volver a un punto de recuperacin particular otra vez, entonces puede liberarlo para que el sistema ahorre algunos recursos. Tenga en cuenta que tanto liberar un punto de recuperacin como volver a l liberar automticamente todos los puntos de recuperacin definidos despus de l.

Todo esto sucede dentro del bloque de transaccin, por lo tanto nada es visible para otras sesiones de la base de datos. Cuando se ejecuta el bloque de transaccin, las acciones ejecutadas se hacen visibles como una unidad para otras sesiones, mientras que las acciones de rollback nunca se hacen visibles.

Retomando el ejemplo de la base de datos bancaria, suponga que se debitan $100 de la cuenta de Alicia y se abonan a la cuenta de Roberto, pero que despus resulta que se debi abonar a la cuenta de Walter. Esto se podra hacer usando un punto de recuperacin:

BEGIN;UPDATE cuentas SET balance = balance - 160.00 WHERE nombre = 'Alicia';SAVEPOINT mi_savepoint;UPDATE cuentas SET balance = balance + 160.00 WHERE nombre = 'Roberto';-- Uy ... no era la cuenta de Roberto sino la de WalterROLLBACK TO mi_savepoint;UPDATE cuentas SET balance = balance + 160.00 WHERE nombre = 'Walter';COMMIT;Este ejemplo, claro, est sobre simplificado, pero existe mucha posibilidad de control en un bloque de transaccin por medio de los puntos de recuperacin. Es ms, ROLLBACK TO es la nica manera de retomar el control de un bloque de transaccin puesto en estado de aborto por el sistema debido a un error, devolverlo completamente y reiniciarlo.