Transacciones en bases de datos

Cuando hablamos de transacciones aplicadas a bases de datos, estas son las operaciones realizadas sobre la misma; puede ser por ejemplo una única operación o bien un conjunto de operaciones agrupadas y aplicadas. Ahora bien, los cambios realizados como parte de una transacción no son visibles para el resto de las conexiones que estén consumiendo los datos de la base de datos, hasta que estos se apliquen como fijos de forma explícita mediante el uso del comando commit. Hay que decir, sin embargo que esto depende del motor de base de datos que estemos utilizando y, de hecho, cuando se trata de SQLite, se aplica el commit de forma implícita en las transacciones realizadas.

Ahora bien, probablemente en determinados casos no querrás realizar un commit automáticamente y dejar, así, fijo el resultado de la operación de forma permanente en la base de datos como resultado de la transacción. El ejemplo clásico que se utiliza para verlo es el de una transacción bancaria, donde un importe determinado deja de figurar en la cuenta del cliente para estar, literalmente, en el limbo a que queda reflejada en la cuenta de destino. Así, cuando el importe está en este particular limbo financiero… ¿qué pasaría si existe algún tipo de problema con la base de datos, una vez que el importe ya no figura en el saldo del emisor, pero tampoco en el saldo del receptor? Para esto está precisamente el uso de las transacciones, puesto que contribuyen a facilitar la integridad en la base de datos y también ofrece ventajas de rendimiento cuando se trata de realizar operaciones sobre una gran cantidad de registros, ya sea crearlos, actualizarlos o borrarlos, por ejemplo.

Pongamos que partimos de la siguiente base:

emisor: 300€
receptor: 150€

Si transferimos un total de 50€ desde el emisor al receptor y realizamos un commit, ya sea manual o automático, entonces los saldos pasarían a ser los siguiente:

emisor: 250€
receptor: 150€
limbo financiero: 50€

Si en el siguiente paso es cuando realizaríamos la operación de agregar esos 50€ finalmente al saldro del receptor, realizando un commit manual o automático con el objeto de reflejar dicho cambio:

emisor: 250€
receptor: 200€
limbo financiero: 0€

Pero si antes de realizar este último paso ocurre algún problema con nuestra aplicación, como un cuelgue, una falta de suministro eléctrico, etc., entonces nos encontraríamos con un grave problema: habrían desaparecido 50€ sin más, estos no figuran en el emisor, pero tampoco habrían llegado al receptor.

Mediante el uso de las transacciones se soluciona este problema, ya que bastaría con abrir o crear una nueva transacción, realizar las dos operaciones y hacer entonces un commit para finalizar la transacción propiamente dicha. De este modo, si ocurriese algún problema antes de finalizar la transacción aun contaríamos con los valores de saldo originales, puesto que las transacciones funcionan bajo la premisa de que o se realizan con éxito todas las operaciones contenidas o bien no se realiza ninguna.

Transacciones y rendimiento

Cada operación de commit implica que los cambios se hacen permanentes en la base de datos, lo que significa escribir sobre el archivo físico entre otras posibles operaciones. Ahora bien, si tenemos que realizar una gran cantidad de operaciones con un commit implícito tras cada una de ellas, como podría ser el caso de la creación de una gran cantidad de registros, entonces ganaremos una buena cantidad de tiempo agrupándolas como parte de una única transacción y realizando así una única operación commit al final de la misma.

El comando utilizado por cada motor de base de datos varía ligeramente; por ejemplo, en el caso de las bases de datos SQLite se realiza con el comando BEGIN TRANSACTION. Una vez finalizada la transacción será cuando apliquemos el comando commit para que los cambios queden fijados de forma permanente; o bien podremos emplear el comando ROLLBACK para cancelar todas las operaciones implicadas en la transacción, devolviendo así la base de datos al estado en el que se encontrase con anterioridad.

Así, y suponiendo que nuestra aplicación estuviese utilizando la variable db para apuntar a nuestra base de datos SQLite, podríamos utilizar el siguiente código para realizar correctamente la operación de transferencia de 50€ correspondiente a nuestro ejemplo inicial:

db.SQLExecute("BEGIN TRANSACTION;")
db.SQLExecute("UPDATE Emisor SET Tipo = 'transferencia', " + _
"cantidad = -50 WHERE cuenta = '001';")
If db.Error Then
MsgBox(db.ErrorMessage)
db.Rollback
Return
End If

db.SQLExecute("UPDATE Receptor SET Type = 'Deposito', " +_
"Amount = 50 WHERE AccountNum = '002';")
If db.Error Then
MsgBox(db.ErrorMessage)
db.Rollback
Return
End If
db.Commit
Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *