Está en la página 1de 10

¿Qué es una transacción?

Una transacción en un Sistema de Gestión de Bases de Datos es un conjunto


de órdenes que se ejecutan formando una unidad de trabajo, es decir, en forma
indivisible o atómica.
Se dice que un SGBD es transaccional si es capaz de mantener la integridad
de los datos, haciendo que estas transacciones no puedan finalizar en un estado
intermedio. Cuando por alguna causa el sistema debe cancelar la transacción,
empieza a deshacer las órdenes ejecutadas hasta dejar la base de datos en su
estado inicial (llamado punto de integridad), como si la orden de la transacción
nunca se hubiese realizado. Una transacción debe contar con ACID (Atomicidad,
Consistencia, Aislamiento y Durabilidad).
MySQL es compatible con varios motores de almacenamiento. InnoDB es
totalmente compatible con ACID. Las transacciones confiables deben ser
compatibles con estas cuatro propiedades.

Las operaciones dentro de una transacción deben ser atómicas. Esto significa
que todas las operaciones tienen éxito o fallan. Esta es la regla de todo o nada. La
consistencia garantiza que la base de datos se encuentre en un estado consistente
una vez finalizada la transacción, los datos son válidos y no hay registros a medio
terminar. Por ejemplo, no quedan clientes sin registros de pago o no hay registros
de pago sin clientes.
El aislamiento es el requisito de que otras operaciones no puedan acceder a
los datos que se han modificado durante una transacción que aún no se ha
completado, el aislamiento ocurre en caso de transacciones concurrentes. Sin
aislamiento, los datos pueden terminar en un estado inconsistente. La durabilidad
es la capacidad del sistema de base de datos para poder recuperarse en caso que
se presenten transacciones comprometidas contra cualquier tipo de falla del
sistema.
Niveles de aislamiento
Pues bien, repasado este concepto ya podemos mostrar los problemas asociados a los

distintos tipos de transacciones:

Dirty reads (Lecturas sucias)


Es el problema más importante de todos. Supone que las transacciones en curso puedan

leer el resultado de otras transacciones aún no confirmadas. Por ejemplo, vamos a suponer que

tenemos dos transacciones activas (A y B).

Inicialmente la transacción A lee un valor X de una tabla que, por ejemplo, es 0. Durante

dicha transacción el valor de X se cambia a 10, pero aún la transacción no se ha completado,

por lo que en la tabla X = 0. Ahora la transacción B accede al valor X y obtiene X = 10 un valor

que está usando A y que aún no se ha cometido. Supongamos que ahora se anula la

transacción A. El resultado sería X = 0 en la tabla y X = 10 en la transacción B por lo que hemos

llegado a un estado muy grave de inconsistencia.

Non-Repeatable reads (Lecturas no repetibles)


Ocurre cuando una transacción activa vuelve a leer un dato cuyo valor difiere con respecto

al de la anterior lectura. Lo vemos más claro con un ejemplo.

Supongamos que una transacción activa, A, lee un valor X = 0. En este momento otra

transacción B modifica el valor de X, por ejemplo X = 10, y se comete dicha transacción. Si

ahora durante la transacción A se vuelve a leer el valor X obtendríamos 10 en lugar del 0 que

se esperaba. Aunque a primera vista este problema no parezca muy importante en realidad sí

que lo es, sobre todo cuando X es una clave primaria o ajena. En este caso se puede originar

una gran pérdida de consistencia en nuestra base de datos.

Phantom reads (Lecturas fantasma)


Este supone el menor problema que se nos puede plantear con respecto a las

transacciones. Sucede cuando una transacción en un momento lanza una consulta de selección

con una condición y recibe en ese momento N filas y posteriormente vuelve a lanzar la misma

consulta junto con la misma condición y recibe M filas con M > N. Esto es debido a que durante
el intervalo que va de la primera a la segunda lectura se insertaron nuevas filas que cumplen la

condición impuesta en la consulta.

Debido a estos problemas el ANSI establece diferentes niveles de aislamiento (isolations

levels) para solventarlos. Hay que tener en cuenta que a mayor nivel de aislamiento mayores

son los sacrificios que se hacen con respecto a la concurrencia y al rendimiento. Vamos a

enumerar los niveles de aislamiento desde el menor hasta el mayor:

Read uncommitted (Lectura sin confirmación): En la práctica casi no se suele utilizar

este nivel de aislamiento ya que es propenso a sufrir todos los problemas anteriormente

descritos. En este nivel una transacción puede ver los resultados de transacciones aún no

cometidas. Podemos apreciar que en este nivel no existe aislamiento alguno entre

transacciones.

Read committed (Lectura confirmada): Es el predeterminado para la mayoría de

gestores de bases de datos relacionales. Supone que dentro de una transacción únicamente se

pueden ver los cambios de las transacciones ya cometidas. Soluciona el problema de las

lecturas sucias, pero no el de las lecturas no repetibles ni tampoco el de las lecturas fantasmas.

Repeatable read (Lectura repetible): Define que cualquier tupla leída durante el

transcurso de una transacción es bloqueada. De esta forma se soluciona, además de las

lecturas sucias, el problema de las lecturas no repetibles. Aunque en dicho nivel se siguen

dando las lecturas fantasmas.

Serializable (Lecturas en serie): Soluciona todos los problemas descritos. Para ello

ordena las transacciones con el objetivo de que no entren en conflicto. Este nivel de aislamiento

es bastante problemático ya que es, con diferencia, el que más sacrifica en rendimiento y

concurrencia.

Nivel de aislamiento Lecturas fantasma Lecturas no repetibles Lecturas sucias

Serializable No No No

Repeatable read Si No No

Read committed Si Si No
Nivel de aislamiento Lecturas fantasma Lecturas no repetibles Lecturas sucias

Read uncommitted Si Si Si

Nota: El nivel de aislamiento predeterminado para MySQL es de Repeatable read (Lectura

repetible).
1
2
3
4
5
6
mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+

El nivel de aislamiento actual se almacena en la variable del servidor tx_isolation.


1
2
3
4
5
6
7
8
mysql> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

mysql> SELECT @@tx_isolation;


+----------------+
| @@tx_isolation |
+----------------+
| SERIALIZABLE |
+----------------+

Podemos cambiar el nivel de aislamiento con la instrucción SET TRANSACTION

ISOLATION LEVEL.

Autocommit
MySQL también comete automáticamente las consultas que no son parte de una
transacción. Los resultados de cualquier consulta ya sea ACTUALIZAR o INSERTAR que no
esté precedida por un START TRANSACTION serán visibles inmediatamente para todas las
conexiones.
1
2
3
4
5
6
mysql> SELECT @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+

La variable autocommit se puede desactivar con la siguiente instrucción.


1
2
3
4
5
6
7
8
mysql> SET autocommit=0;

mysql> SELECT @@autocommit;


+--------------+
| @@autocommit |
+--------------+
| 0 |
+--------------+

Ahora vamos a demostrar la variable autocommit. La variable autocommit está activada.

Creamos una tabla de Test con el motor de almacenamiento InnoDB, que admite transacciones.
1
2
3
4
5
6
7
8
mysql> SELECT @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+

CREATE TABLE Test(Num INTEGER NOT NULL) engine=InnoDB;

Insertamos tres registros en la tabla Test. Los valores se cometen de inmediato.


1
2
3
4
5
6
7
8
9
10
mysql> INSERT INTO Test VALUES (1), (2), (3);

mysql> SELECT * FROM Test;


+-----+
| Num |
+-----+
| 1 |
| 2 |
| 3 |
+-----+

Ahora desactivamos la variable autocommit, insertamos dos valores y seleccionamos todos

los datos de la tabla. Ahora tenemos 5 filas en la tabla.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql> SET autocommit=0;

mysql> INSERT INTO Test VALUES (4), (5);

mysql> SELECT * FROM Test;


+-----+
| Num |
+-----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+-----+

Sin embargo, los datos no se escriben permanentemente en la tabla. Con la

instrucción ROLLBACK, volvemos al estado anterior.


1
2
3
4
5
6
7
8
9
10
mysql> ROLLBACK;

mysql> SELECT * FROM Test;


+-----+
| Num |
+-----+
| 1 |
| 2 |
| 3 |
+-----+

Ahora insertamos los valores 4, 5 nuevamente. Esta vez, los registros se guardan

permanentemente con la instrucción COMMIT. La instrucción ROLLBACK ahora no tiene

ningún efecto.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mysql> INSERT INTO Test VALUES (4), (5);

mysql> COMMIT;

mysql> ROLLBACK;

mysql> SELECT * FROM Test;


+-----+
| Num |
+-----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+-----+

Transacciones
Con autocommit habilitado, cada instrucción SQL se ajusta automáticamente en su propia

transacción. Para comenzar nuestra propia transacción, debemos ejecutar la

instrucción START TRANSACTION. La transacción se termina más tarde con las

instrucciones COMMIT o ROLLBACK. Se pueden ejecutar múltiples declaraciones en el cuerpo

de la transacción.
Trabajaremos con la misma tabla Test. Truncamos los datos en la tabla.
1
2
3
4
5
mysql> TRUNCATE Test;
Query OK, 0 rows affected (0.02 sec)

mysql> SELECT * FROM Test;


Empty set (0.00 sec)

Comenzamos una transacción e insertamos cuatro registros en la tabla. Los valores aún

no están cometidos. Desde la conexión actual, las registros son visibles.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> START TRANSACTION;
mysql> INSERT INTO Test VALUES (1), (2);

mysql> INSERT INTO Test VALUES (3), (4);

mysql> SELECT * FROM Test;


+-----+
| Num |
+-----+
| 1 |
| 2 |
| 3 |
| 4 |
+-----+

Sin embargo, desde una conexión diferente, la tabla Test está vacía. Abrimos una nueva

conexión MySQL. Esta es una conexión diferente de la que insertamos los registros. Desde esta

conexión, los valores aún no son visibles.


1
2
3
4
5
6
7
8
9
10
$ mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 65
Server version: 5.1.41-3ubuntu12.9 (Ubuntu)

Type 'help;' or '\h' for help. Type '\c' to clear the current input state
ment.

mysql> SELECT * FROM mydb.Test;


Empty set (0.00 sec)

Finalmente, la ejecutamos la instrucción COMMIT en la primera conexión para cometer los

datos en la tabla. Ahora los registros son visibles en ambas conexiones.


mysql> COMMIT;

Comenzamos otra transacción. Esta vez los datos se revertirán.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> START TRANSACTION;

mysql> INSERT INTO Test VALUES (5), (6);

mysql> INSERT INTO Test VALUES (7), (8);

mysql> ROLLBACK;

mysql> SELECT * FROM Test;


+-----+
| Num |
+-----+
| 1 |
| 2 |
| 3 |
| 4 |
+-----+

En el código SQL anterior, comenzamos una nueva transacción. Insertamos cuatro valores

en la tabla Test. Revertimos los cambios con la instrucción ROLLBACK. La consulta posterior

de la tabla muestra que los datos no se guardaron en la tabla.

También podría gustarte