Você está na página 1de 9

Transacciones en MySQL El servidor de bases de datos MySQL soporta distintos tipos de tablas, tales como ISAM, MyISAM, InnoDB

y BDB (Berkeley Databa se). De stos, InnoDB es el tipo de tabla ms importante (despus del tipo predeterminado, MyISAM), y merece una atencin especial. Las tablas del tipo InnoDB estn estructuradas de forma distinta que MyISAM, ya que se almacenan en un slo archivo en lugar de tres, y sus principales caractersticas son que permite trabajar con transacciones, y definir regl as de integridad referencial. El soporte de transacciones que provee MySQL no es algo nuevo en MySQL 4, ya que desde la versin 3.23 se poda hacer uso de tablas InnoDB, la nica diferencia es que con la llegada de la versin 4.0 de MySQL, el soporte para este tipo de tablas es habilitado por default. Las transacciones aportan una fiabilidad superior a las bases de datos. Si disponemos de una serie de consultas SQL que deben ejecutarse en conjunto, con el uso de transacciones podemos tener la certeza de qu e nunca nos quedaremos a medio camino de su ejecucin. De hecho, podramos decir que las transacciones aportan una caracterstica de "deshacer" a las aplicaciones de bases de datos. Para este fin, las tablas que soportan transacciones, como es el caso de I nnoDB, son mucho ms seguras y fciles de recuperar si se produce algn fallo en el servidor, ya que las consultas se ejecutan o no en su totalidad. Por otra parte, las transacciones pueden h acer que las consultas tarden ms tiempo en ejecutarse. Seguramente alguna vez hemos escuchado hablar acerca de las transacciones, pero probablemente no entendemos bien lo que son, y como deben de ser usadas. La idea de este artculo es presentar algunos ejemplos para mostrar que no es nada complicado, y difcil de aprender. En este artculo se asume que se cuenta ya con un servidor MySQL con soporte para el tipo de tablas InnoDB. En nuestro caso h aremos uso de un servidor MySQL 4.013 ejecutndose en un sistema MSWindows. Para asegurarnos que tenemos soporte para el tipo de tablas InnoDB podemos ejecutar la siguiente sentencia: mysql> SHOW VARIABLES LIKE '%innodb%'; +---------------------------------+------------+ | Variable_name | Value | +---------------------------------+------------+ | have_innodb | YES | | innodb_additional_mem_pool_size | 1048576 | | innodb_buffer_pool_size | 8388608 | | innodb_data_file_path | ibdata:30M | | innodb_data_home_dir | | | innodb_file_io_threads | 4 | | innodb_force_recovery | 0 | | innodb_thread_concurrency | 8 | | innodb_flush_log_at_trx_commit | 1 | | innodb_fast_shutdown | ON | | innodb_flush_method | | | innodb_lock_wait_timeout | 50 | | innodb_log_arch_dir | .\ | | innodb_log_archive | OFF | | innodb_log_buffer_size | 1048576 | | innodb_log_file_size | 5242880 | | innodb_log_files_in_group | 2 | | innodb_log_group_home_dir | .\ | | innodb_mirrored_log_groups | 1 | | innodb_max_dirty_pages_pct | 90 | +---------------------------------+------------+ 20 rows in set (0.00 sec) La variable ms importante es por supuesto have_innodb que tiene el valor YES.

En efecto, una de las principales caractersticas de las tablas del tipo InnoDB es que pueden trabajar con transacciones, o s entencias SQL que son agrupadas como una sola. Un ejemplo tpico de esto es una transaccin bancaria. Por ejemplo, si una cantidad de dinero es transferida de la cuenta de una persona a otra, se requerirn por lo menos dos consultas: UPDATE cuentas SET balance = balance - cantidad_transferida WHERE cliente = persona1; UPDATE cuentas SET balance = balance + cantidad_transferida WHERE cliente = persona2; Estas dos consultas deben trabajar bien, pero que sucede si ocurre algn imprevisto y "se cae" el sistema despus de que se ejecuta la primer consulta, pero la segunda an no se ha completado?. La persona1 tendr una cantidad de dinero removida de su cuenta, y creer que ha realizado su pago, sin embargo, la persona2 estar enfadada puesto que pensar que no se le ha depositado el dinero que le de ben. En este ejemplo tan sencillo se ilustra la necesidad de que las consultas sean ejecutadas de manera conjunta, o en su caso, que no se ejecute ninguna de ellas. Es aqu donde las transacciones toman un papel muy importante. Los pasos para usar transacciones en MySQL son: Iniciar una transaccin con el uso de la sentencia BEGIN. Actualizar, insertar o eliminar registros en la base de datos. Si se quieren los cambios a la base de datos, completar la transaccin con el uso de la sentencia COMMIT. nicamente cuando s e procesa un COMMIT los cambios hechos por las consultas sern permanentes. Si sucede algn problema, podemos hacer uso de la sentencia ROLLBACK para cancelar los cambios que han sido realizados por la s consultas que han sido ejecutadas hasta el momento. Vamos a ejecutar algunas consultas para ver como trabajan las transacciones. Lo primero que tenemos que hacer es crear una tabla del tipo InnoDB e insertar algunos datos. Para crear una tabla InnoDB, procedemos con el cdigo SQL estndar CREATE TABLE, pero deb emos especificar que se trata de una tabla del tipo InnoDB (TYPE= InnoDB). Esto es aplicable a cualquier tipo de tabla, pero cuando no se especifica nada, MySQL supone que se trata de una tabla MyISAM. mysql> CREATE TABLE innotest (campo INT NOT NULL PRIMARY KEY) TYPE = InnoDB; Query OK, 0 rows affected (0.10 sec) mysql> INSERT INTO innotest VALUES(1); Query OK, 1 row affected (0.08 sec) mysql> INSERT INTO innotest VALUES(2); Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO innotest VALUES(3); Query OK, 1 row affected (0.04 sec) mysql> SELECT * FROM innotest; +-------+ | campo | +-------+ |1| |2| |3| +-------+ 3 rows in set (0.00 sec) De acuerdo, nada espectacular. Ahora veamos como usar transacciones. mysql> BEGIN; Query OK, 0 rows affected (0.01 sec) mysql> INSERT INTO innotest VALUES(4);

Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM innotest; +-------+ | campo | +-------+ |1| |2| |3| |4| +-------+ 4 rows in set (0.00 sec) Si en este momento ejecutamos un ROLLBACK, la transaccin no ser completada, y los cambios realizados sobre la tabla no tendrn efecto. mysql> ROLLBACK; Query OK, 0 rows affected (0.06 sec) mysql> SELECT * FROM innotest; +-------+ | campo | +-------+ |1| |2| |3| +-------+ 3 rows in set (0.00 sec) Ahora vamos a ver que sucede si perdemos la conexin al servidor antes de que la transaccin sea completada. mysql> BEGIN; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO innotest VALUES(4); Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM innotest; +-------+ | campo | +-------+ |1| |2| |3| |4| +-------+ 4 rows in set (0.00 sec) mysql> EXIT; Bye Cuando obtengamos de nuevo la conexin, podemos verificar que el registro no se insert, ya que la transaccin no fue comple tada. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 449 to server version: 4.0.13 Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> SELECT * FROM innotest; +-------+ | campo |

+-------+ |1| |2| |3| +-------+ 3 rows in set (0.00 sec) Ahora vamos a repetir la sentencia INSERT ejecutada anteriormente, pero haremos un COMMIT antes de perder la conexin al serv idor al salir del monitor de MySQL. mysql> BEGIN; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO innotest VALUES(4); Query OK, 1 row affected (0.00 sec) mysql> COMMIT; Query OK, 0 rows affected (0.02 sec) mysql> EXIT; Bye Una vez que hacemos un COMMIT, la transaccin es completada, y todas las sentencias SQL que han sido ejecutada s previamente afectan de manera permanente a las tablas de la base de datos. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 450 to server version: 4.0.13 Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> SELECT * FROM innotest; +-------+ | campo | +-------+ |1| |2| |3| |4| +-------+ 4 rows in set (0.00 sec) Lecturas consistentes Por default, las tablas InnoDB ejecutan un lectura consistente (consistent read). Esto significa que cuando una sentencia SELECT es ejecutada, MySQL regresa los valores presentes en la base de datos hasta la transaccin ms reciente que ha sido completada. Si alguna transaccin est en progreso, los cambios hechos por alguna sentenci a INSERT o UPDATE no sern reflejados. Sin embargo, existe una excepcin: las transacciones abiertas si pueden ver sus propios cambios. Para demostrar esto, necesitamos establecer dos conexiones al servidor MySQL. Primero agregaremos un registro dentro de una transaccin con la primera conexin (ID 524): Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 524 to server version: 4.0.13 Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> BEGIN; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO innotest VALUES(5); Query OK, 1 row affected (0.00 sec) Ahora, desde la segunda conexin (ID 525) consultamos los datos de nuestra tabla. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 525 to server version: 4.0.13 Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> SELECT * FROM innotest;

+-------+ | campo | +-------+ |1| |2| |3| |4| +-------+ 4 rows in set (0.00 sec) Como se puede observar, el registro que hemos insertado desde la 1ra. conexin no es regresado puesto que forma parte de una transaccin que no ha sido completada. Ahora, desde la 1ra. conexin ejecutamos la misma consulta SELECT. mysql> SELECT * FROM innotest; +-------+ | campo | +-------+ |1| |2| |3| |4| |5| +-------+ 5 rows in set (0.00 sec) Despus de completar la transaccin con una sentencia COMMIT en la 1ra. conexin podremos verificar que desde la 2da. conexi n los cambios ya son visibles. mysql> SELECT * FROM innotest; +-------+ | campo | +-------+ |1| |2| |3| |4| |5| +-------+ 5 rows in set (0.00 sec) Otro ejemplo En el ejemplo anterior hemos usado nicamente sentencias INSERT, sin embargo, sucede lo mismo con sentencias UPDATE o DELETE. Vamos a crear una sencilla tabla llamada ventas que sea del tipo InnoDB. mysql> CREATE TABLE ventas( -> id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, -> producto VARCHAR(30) NOT NULL, -> cantidad TINYINT NOT NULL) TYPE = InnoDB; Query OK, 0 rows affected (0.96 sec) Insertamos un registro. mysql> INSERT INTO ventas VALUES(0,'Gansito marinela',3); Query OK, 1 row affected (0.16 sec) mysql> SELECT * FROM ventas; +----+------------------+----------+ | id | producto | cantidad | +----+------------------+----------+

| 1 | Gansito marinela | 3 | +----+------------------+----------+ 1 row in set (0.01 sec) Ahora vamos a iniciar una transaccin con la sentencia BEGIN. mysql> BEGIN; Query OK, 0 rows affected (0.00 sec) Actualizamos el registro. mysql> UPDATE ventas SET cantidad=4 WHERE id=1; Query OK, 1 row affected (0.07 sec) Lneas correspondientes: 1 Cambiadas: 1 Avisos: 0 Verificamos que los cambios han sucedido. mysql> SELECT * FROM ventas; +----+------------------+----------+ | id | producto | cantidad | +----+------------------+----------+ | 1 | Gansito marinela | 4 | +----+------------------+----------+ 1 row in set (0.00 sec) Si queremos deshacer los cambios, entonces ejecutamos un ROLLBACK. mysql> ROLLBACK; Query OK, 0 rows affected (0.06 sec) Verificamos que se deshicieron los cambios. mysql> SELECT * FROM ventas; +----+------------------+----------+ | id | producto | cantidad | +----+------------------+----------+ | 1 | Gansito marinela | 3 | +----+------------------+----------+ 1 row in set (0.00 sec) Vamos a actualizar el registro usando otra transaccin. mysql> BEGIN; Query OK, 0 rows affected (0.00 sec) mysql> UPDATE ventas SET cantidad=2 WHERE id=1; Query OK, 1 row affected (0.00 sec) Lneas correspondientes: 1 Cambiadas: 1 Avisos: 0 mysql> SELECT * FROM ventas; +----+------------------+----------+ | id | producto | cantidad | +----+------------------+----------+ | 1 | Gansito marinela | 2 | +----+------------------+----------+ 1 row in set (0.00 sec) Vamos a confirmar que deseamos los cambios. mysql> COMMIT; Query OK, 0 rows affected (0.05 sec) En este momento los cambios son permanentes y definitivos. mysql> SELECT * FROM ventas; +----+------------------+----------+ | id | producto | cantidad | +----+------------------+----------+ | 1 | Gansito marinela | 2 |

+----+------------------+----------+ 1 row in set (0.00 sec)

Transacciones en MySQL. ROLLBACK y COMMIT


Una transaccin en MySQL es una secuencia de una o ms sentencias SQL que juntas forman una unidad de trabajo. Imagina que quieres borrar uno o varios registros de una tabla, pero te equivocas y eliminas todos los registros de la tabla. Existe alguna forma de subsanar el error y dar marcha atrs para recuperar los registros eliminados? La respuesta es s, utilizando transacciones. Por defecto MySQL funciona en modo autocommit. Esto quiere decir que se confirma (COMMIT) cada sentencia ejecutada. Los pasos para iniciar una transaccin son los siguientes:
Se comienza una transaccin con la sentencia START TRANSACTION. Si se realizan modificaciones en la base de datos y queremos volver atrs y cancelar los cambios realizados hasta el momento, utilizaremos la sentencia ROLLBACK. Si queremos confirmar los cambios realizados en la base de datos, utilizaremos la sentencia COMMIT, lo cual implica tambin que termina la transaccin. Si queremos comenzar una nueva transaccin, usaremos START TRANSACTION.

Nota: para que las transacciones funcionen correctamente, debemos utilizar tablas InnoDB. Veamos un ejemplo. Disponemos de la tabla EMPLE, que est formada por los campos que se muestran en la imagen.

A continuacin comenzamos una transaccin con START TRANSACTION.

Modificamos el salario de todos los empleados de la tabla EMPLE, con la siguiente sentencia SQL.
update emple set salario=1000;

Observamos a continuacin que se ha modificado el salario de todos los empleados.

Deshacemos el trabajo ya que nos hemos equivocado. Para ello utilizamos la sentencia ROLLBACK.

Y comprobamos a continuacin que la tabla vuelve a su estado original.

Si queremos validar los cambios en la base de datos, completaremos la transaccin con el uso de la sentencia COMMIT. Si ejecutamos ROLLBACK justo despus de hacer el COMMIT, los cambios realizados sobre la base de datos permanecern, debido a que anteriormente se valid la transaccin.

Você também pode gostar