En el artículo: 3 preguntas sobre transacciones habías podido auto-evaluarte para comprobar tu entendimiento sobre las transacciones del Firebird. ¿Sabes cuáles son las respuestas correctas?. Veamos:

Pregunta 1. Una transacción realizó tres inserciones. El tercer INSERT elevó una excepción. ¿Es posible finalizar esa transacción con un COMMIT exitoso?

[Sí]   [No]

La respuesta es . El COMMIT y el ROLLBACK no dependen de las excepciones. Las excepciones son los mensajes de error que el Servidor le envía al Cliente para informarle de que algo está mal. Y lo normal por supuesto es hacer el COMMIT solamente a las transacciones que no elevaron una excepción pero eso no es obligatorio.

Veamos un ejemplo: Tenemos una tabla llamada BANCOS con estas filas:

TRANSACCION1

Captura 1. Si haces clic en la imagen la verás más grande

Donde la columna BAN_IDENTI es la Primary Key y por lo tanto no puede repetirse, pero escribimos:

Listado 1.

INSERT INTO BANCOS (BAN_IDENTI, BAN_NOMBRE) VALUES(3, 'BANCO NRO 3');
INSERT INTO BANCOS (BAN_IDENTI, BAN_NOMBRE) VALUES(1, 'BANCO REPETIDO');

Y el Firebird nos responde con el mensaje: ‘Violation of PRIMARY or UNIQUE KEY constraint “PK_BANCOS” on table “BANCOS”. Problematic key value is (“BAN_IDENTI” = 1).’

El segundo INSERT falló porque quisimos poner en la columna BAN_IDENTI un valor que ya existía en esa columna, algo que no está permitido. Sin embargo, ¿podemos finalizar esa transacción con un COMMIT?

Listado 2.

COMMIT

Pues sí, sin problema. Aceptó el COMMIT. La fila cuyo valor de BAN_IDENTI estaba repetido no fue insertada, pero la transacción igualmente finalizó con un COMMIT. ¿Y qué pasó con la primera fila, fue insertada o no? Veamos.

Listado 3.

SELECT
   BAN_IDENTI,
   BAN_NOMBRE
FROM
   BANCOS

TRANSACCION2

Captura 2. Si haces clic en la imagen la verás más grande

Pues sí, fue insertada. La fila no insertada fue la que tenía problemas, la fila que estaba correcta fue insertada.

En general, lo normal (y la mayor parte de las veces lo correcto) es que si una transacción eleva una excepción se finalice esa transacción con un ROLLBACK, pero también podemos finalizarla con un COMMIT, como acabamos de ver. En este caso, las instrucciones que no elevaron una excepción y que se ejecutaron antes de la que elevó la excepción serán confirmadas.

Cambiemos el orden de los INSERT y veamos que ocurre:

Listado 4.

INSERT INTO BANCOS (BAN_IDENTI, BAN_NOMBRE) VALUES(1, 'BANCO REPETIDO');
INSERT INTO BANCOS (BAN_IDENTI, BAN_NOMBRE) VALUES(3, 'BANCO NRO 3');

En este caso, como fue el primer INSERT el que elevó la excepción, el segundo INSERT jamás se ejecutará y nuestra tabla de BANCOS quedará sin modificarse.

TRANSACCION1

Captura 3. Si haces clic en la imagen la verás más grande

La Captura 3. nos muestra como quedó la tabla de BANCOS después de ejecutar el Listado 4., o sea que como el primer INSERT falló, el segundo INSERT nunca se ejecutó y la tabla de BANCOS quedó exactamente igual a como estaba antes.

Pregunta 2. La tabla MiTabla tiene 10 filas. Simultáneamente 3 transacciones se iniciaron y cada transacción insertó una fila en MiTabla. En la tercera transacción se escribió:

Listado 5.

SELECT
   COUNT(*)
FROM
   MiTabla

¿Cuál será el resultado mostrado?

[10]    [11]    [12]    [13]

El resultado será 11. Al iniciarse cada transacción para ella la tabla MiTabla tiene 10 filas. Una transacción no puede saber lo que las demás transacciones están haciendo.  Pero sí sabe muy bien lo que ella misma está haciendo. Entonces, para la tercera transacción inicialmente MiTabla tenía 10 filas, le insertó una fila y por lo tanto al escribir el SELECT obtendrá el resultado de 11. Las 10 filas iniciales más la fila que ella insertó.

Pregunta 3. Tenemos un generador cuyo nombre es MiGenerador y su valor es 10. Dos transacciones, T1 y T2, se están ejecutando simultáneamente. En la transacción T1 ejecutamos: GEN_ID(MiGenerador, 1) y en la transacción T2 ejecutamos: GEN_ID(MiGenerador, 1)

La transacción T1 finalizó con un COMMIT y la transacción T2 finalizó con un ROLLBACK. ¿Cuál es el valor de MiGenerador después de eso?

[10]    [11]    [12]

El valor de MiGenerador es 12. Los generadores (también llamados secuencias) están afuera de las transacciones, no importa como finalice una transacción, si con COMMIT o con ROLLBACK, eso no les afecta a los generadores.

Entonces, MiGenerador tenía un valor inicial de 10, la primera función GEN_ID() en ejecutarse lo incrementó a 11 y la segunda función GEN_ID() en ejecutarse lo incrementó a 12.

Artículos relacionados:

3 preguntas sobre transacciones

El índice del blog Firebird21

El foro del blog Firebird21

Anuncios