13.4. Comandos transaccionales y de bloqueo de MySQL

MySQL 5.0

13.4. Comandos transaccionales y de bloqueo de MySQL

13.4.1. Sintaxis de START TRANSACTION, COMMIT y ROLLBACK

Por defecto, MySQL se ejecuta con el modo autocommit activado. Esto significa que en cuanto ejecute un comando que actualice (modifique) una tabla, MySQL almacena la actualización en disco.

Si usa tablas transaccionales (como o ), puede desactivar el modo autocommit con el siguiente comando:

SET AUTOCOMMIT=0;

Tras deshabilitar el modo autocommit poniendo la variable a cero, debe usar para almacenar los cambios en disco o si quiere ignorar los cambios hechos desde el comienzo de la transacción.

Si quiere deshabilitar el modo autocommit para una serie única de comandos, puede usar el comando :

START TRANSACTION;
SELECT @A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET summary=@A WHERE type=1;
COMMIT;

Con , autocommit permanece deshabilitado hasta el final de la transacción con o . El modo autocommit vuelve a su estado prévio.

y se soportan como alias para para iniciar una transacción. es sintaxis SQL estándar y es la forma recomendada para iniciar una transacción ad-hoc . El comando difiere del uso de la palabra clave que comienza un comando compuesto . El último no comienza una transacción. Consulte Sección 19.2.7, “Sentencia compuesta .

Puede comenzar una transacción así:

START TRANSACTION WITH CONSISTENT SNAPSHOT;

La cláusula comienza una lectura consistente para motores de almacenamiento capaces de ello. Actualmente, esto se aplica sólo a . El efecto es el mismo que realizar un seguido por un desde cualquier tabla . Consulte Sección 15.10.4, “Lecturas consistentes que no bloquean”.

Comenzar una transacción provoca que se realice un implícito.

Tenga en cuenta que si no usa tablas transaccionales, cualquier cambio se almacena de golpe, a pesar del estado del modo autocommit .

Si realiza un comando tras actualizar una tabla no transaccional dentro de una transacción, ocurre una advertencia . Los cambios en tablas transaccionales se deshacen, pero no los cambios en tablas no transaccionales.

Cada transacción se almacena en el log binario en un trozo, hasta . Las transacciones que se deshacen no se loguean. (Exceción: Las modificaciones a tablas no transaccionales no pueden deshacerse. Si una transacción que se deshace incluye modificaciones a tablas no transaccionales, la transacción entera se loguea con un comando al final para asegurar que las modificaciones a estas tablas se replican.) Consulte Sección 5.10.3, “El registro binario (Binary Log)”.

Puede cambiar el nivel de aislamiento para transacciones con . Consulte Sección 13.4.6, “Sintaxis de .

Deshacer puede ser una operación lenta que puede ocurrir sin que el usuario lo haya pedido explícitamente (por ejemplo, cuando ocurre un error). Debido a ello, en MySQL 5.0 muestra en la columna para la conexión durante rollbacks implícitos y explícitos (comando SQL ).

13.4.2. Sentencias que no se pueden deshacer

Algunos comandos no pueden deshacerse. En general, esto incluye comandos del lenguaje de definición de datos (DDL), tales como los que crean y borran bases de datos, los que crean, borran o alteran tablas o rutinas almacenadas.

Debe designar que sus transacciones no incluyan tales comandos. Si realiza un comando pronto en una transacción que no puede deshacerse, y luego un comando posterior falla, el efecto global de la transacción no puede deshacerse mediante un comando .

13.4.3. Sentencias que causan una ejecución (commit) implícita

Cada uno de los comandos siguientes (y cualquier sinónimo de los mismos) terminan una transacción implícitamente, como si hubiera realizado un antes de ejecutar el comando:

también realiza un commit de una transacción si hay cualquier tabla bloqueada.

Las transacciones no pueden anidarse. Esto es una consecuencia del implícito realizado por cualquier transacción actual cuando realiza un comando o uno de sus sinónimos.

13.4.4. Sintaxis de SAVEPOINT y ROLLBACK TO SAVEPOINT

SAVEPOINT identifier
ROLLBACK TO SAVEPOINT identifier

En MySQL 5.0, soporta los comandos SQL y .

El comando crea un punto dentro de una transacción con un nombre . Si la transacción actual tiene un punto con el mismo nombre, el antiguo se borra y se crea el nuevo.

El comando deshace una transacción hasta el punto nombrado. Las modificaciones que la transacción actual hace al registro tras el punto se deshacen en el rollback, pero no libera los bloqueos de registro que se almacenaron en memoria tras el punto . (Tenga en cuenta que para un nuevo registro insertado, la información de bloqueo se realiza a partir del ID de transacción almacenado en el registro; el bloqueo no se almacena separadamente en memoria. En este caso, el bloqueo de registro se libera al deshacerse todo.) Los puntos creados tras el punto nombrado se borran.

Si un comando retorna el siguiente error, significa que no existe ningún punto con el nombre especificado:

ERROR 1181: Got error 153 during ROLLBACK

Todos los puntos de la transacción actual se borran si ejecuta un , o un que no nombre ningún punto.

13.4.5. Sintaxis de LOCK TABLES y UNLOCK TABLES

LOCK TABLES
     [AS ] {READ [LOCAL] | [LOW_PRIORITY] WRITE}
    [,  [AS ] {READ [LOCAL] | [LOW_PRIORITY] WRITE}] ...
UNLOCK TABLES

bloquea tablas para el flujo actual. Si alguna de las tablas la bloquea otro flujo, bloquea hasta que pueden adquirirse todos los bloqueos. libera cualquier bloqueo realizado por el flujo actual. Todas las tablas bloqueadas por el flujo actual se liberan implícitamente cuando el flujo reliza otro , o cuando la conexión con el servidor se cierra.

Un bloqueo de tabla protege sólo contra lecturtas inapropoadas o escrituras de otros clientes. El cliente que tenga el bloqueo, incluso un bloqueo de lectura, puede realizar operaciones a nivel de tabla tales como .

Tenga en cuenta lo siguiente a pesar del uso de con tablas transaccionales:

  • no es una operación transaccional y hace un commit implícito de cualquier transacción activa antes de tratar de bloquear las tablas. También, comenzar una transacción (por ejemplo, con ) realiza un implícito. (Consulte Sección 13.4.3, “Sentencias que causan una ejecución (commit) implícita”.)

  • La forma correcta de usar con tablas transaccionales,como , es poner y no llamar a hasta que hace un commit de la transacción explícitamente. Cuando llama a , internamente realiza su propio bloqueo de tabla, y MySQL realiza su propio bloqueo de tabla. libera su bloqueo de tabla en el siguiente commit, pero para que MySQL libere su bloqueo de tabla, debe llamar a . No debe tener , porque entonces libera su bloqueo de tabla inmediatamente tras la llamada de , y los deadlocks pueden ocurrir fácilmente. (Tenga en cuenta que en MySQL 5.0, no adquirimos el bloqueo de tabla en absoluto si , para ayudar a aplicaciones antiguas a envitar deadlocks.)

  • no libera bloqueos de tablas no transaccionales de MySQL.

Para usar en MySQL 5.0, debe tener el permiso y el permiso para las tablas involucradas.

La razón principal para usar es para emular transacciones o para obtener más velocidad al actualizar tablas. Esto se explica con más detalle posteriormente.

Si un flujo obtiene un bloqueo en una tabla, ese flujo (y todos los otros) sólo pueden leer de la tabla. Si un flujo obtiene un bloqueo en una tabla, sólo el flujo con el bloqueo puede escribir a la tabla. El resto de flujos se bloquean hasta que se libera el bloqueo.

La diferencia entre y es que permite comandos no conflictivos (inserciones concurrentes) se ejecuten mientras se mantiene el bloqueo. Sin embargo, esto no puede usarse si va a manipular los ficheros de base de datos fuera de MySQL mientras mantiene el bloqueo. Para tablas , esencialmente no hace nada: No bloquea la tabla. Para tablas , el uso de está obsoleto ya que una consistente hace lo mismo, y no se necesitan bloqueos.

Cuando usa , debe bloquear todas las tablas que va a usar en sus consultas. Mientras los bloqueos obtenidos con un comando están en efecto, no puede acceder a ninguna tabla que no estuviera bloqueada por el comando. Además, no puede usar una tabla bloqueada varias veces en una consulta --- use alias para ello. Tenga en cuenta que en este caso, debe tener un bloqueo separado para cada alias.

mysql> LOCK TABLE t WRITE, t AS t1 WRITE;
mysql> INSERT INTO t SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> INSERT INTO t SELECT * FROM t AS t1;

Si sus consultas se refieren a una tabla que use un alias, debe bloquear la tabla que usa el mismo alias. No funciona bloquear la tabla sin especificar el alias:

mysql> LOCK TABLE t READ;
mysql> SELECT * FROM t AS myalias;
ERROR 1100: Table 'myalias' was not locked with LOCK TABLES

Si bloquea una tabla usando un alias, debe referirse a ella en sus consultas usando este alias:

mysql> LOCK TABLE t AS myalias READ;
mysql> SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> SELECT * FROM t AS myalias;

bloquea normalmente teniendo una prioridad superior que al bloquear para asegurar que las actualizaciones se procesan en cuanto se puede. Esto significa que si un flujo obtiene un bloqueo y luego otro flujo pide un bloqueo , las peticiones de bloqueo posteriores esperan hasta que el flujo quita el bloqueo. Puede usar bloqueos para permitir a otros flujos que obtengan bloqueos mientras el flujo está en espera para el bloqueo . Debe usar bloqueos sólo si está seguro que habrá un momento sin flujos con bloqueos .

funciona como sigue:

  1. Ordena todas las tablas a ser bloqueadas en un orden definido internamente. Desde el punto de vista del usuario, este orden es indefinido.

  2. Si una tabla se bloquea con bloqueo de escritura y lectura, pone el bloqueo de lectura antes del de escritura.

  3. Bloquea una tabla cada vez hasta que el flujo obtiene todos los bloqueos.

Esta política asegura un bloqueo de tablas libre de deadlocks. Sin embargo hay otros puntos que debe tener en cuenta respecto a esta política:

Si está usando un bloqueo para una tabla, sólo significa que MySQL espera para este bloqueo particular hasta que no hay flujos que quieren un bloqueo . Cuando el flujo ha obtenido el bloqueo y está esperando para obtener un bloqueo para la siguiente tabla en la lista, todos los otros flujos esperan hasta que el bloqueo se libera. Si esto es un problema con su aplicación, debe considerar convertir algunas de sus tablas a transaccionales.

Puede usar para terminar un flujo que está esperando para un bloqueo de tabla. Consulte Sección 13.5.5.3, “Sintaxis de .

Tenga en cuenta que no debe bloquear ninguna tabla que esté usando con ya que en tal caso el lo realiza un flujo separado.

Normalmente, no tiene que bloquear tablas, ya que todos los comandos son atómicos, ningún otro flujo puede interferir con ningún otro que está ejecutando comandos SQL . Hay algunos casos en que no debe bloquear tablas de ningún modo:

  • Si va a ejecutar varias operaciones en un conjunto de tablas , es mucho más rápido bloquear las tablas que va a usar. Bloquear tablas acelera la inserción, las actualizaciones, y los borrados. Por contra, ningún flujo puede actualizar una tabla con un bloqueo (incluyendo el que tiene el bloqueo) y ningún flujo puede acceder a una tabla con un bloqueo distinto al que tiene el bloqueo.

    La razón que algunas operaciones sean más rápidas bajo es que MySQL no vuelca la caché de claves para la tabla bloqueada hasta que se llama a . Normalmente, la caché de claves se vuelca tras cada comando SQL.

  • Si usa un motor de almacenamiento en MySQL que no soporta transacciones, debe usar si quiere asegurarse que ningún otro flujo se ejecute entre un y un . El ejemplo mostrado necesita para ejecutarse sin problemas:

    mysql> LOCK TABLES trans READ, customer WRITE;
    mysql> SELECT SUM(value) FROM trans WHERE customer_id=;
    mysql> UPDATE customer
        ->     SET total_value=
        ->     WHERE customer_id=;
    mysql> UNLOCK TABLES;
    

    Sin , es posible que otro flujo pueda insertar un nuevo registro en la tabla entre la ejecución del comando y .

Puede evitar usar en varios casos usando actualizaciones relativas (=+) o la función , Consulte Sección 1.7.5.3, “Transacciones y operaciones atómicas”.

Puede evitar bloquear tablas en algunos casos usando las funciones de bloqueo de nivel de usuario y . Estos bloqueos se guardan en una tabla hash en el servidor e implementa y para alta velocidad. Consulte Sección 12.9.4, “Funciones varias”.

Consulte Sección 7.3.1, “Métodos de bloqueo”, para más información acerca de la política de bloqueo.

Puede bloquear todas las tablas en todas las bases de datos con bloqueos de lectura con el comando . Consulte Sección 13.5.5.2, “Sintaxis de . Esta es una forma muy conveniente para obtener copias de seguridad si tiene un sistema de ficheros como Veritas que puede obtener el estado en un punto temporal.

Nota: Si usa en una tabla bloqueada, puede desbloquearse. Consulte Sección A.7.1, “Problemas con .

13.4.6. Sintaxis de SET TRANSACTION

SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL
{ READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }

Este comando prepara el nivel de aislamiento de transacción para la siguiente transacción, globalmente, o para la sesión actual.

El comportamiento por defecto de es poner el nivel de aislammiento para la siguiente transacción (que no ha empezado todavía). Si usa lka palabra clave el comando pone el nivel de aislamiento de transacción por defecto globalmente para todas las transacciones creadas desde ese momento. Las conexiones existentes no se ven afectadas. Necesita el permiso para hacerlo. Usar la palabra clave determina el nivel de transacción para todas las transacciones futuras realizadas en la conexión actual.

Para descripciones del nivel de aislamiento de cada transacción , consulte Sección 15.10.3, “ y . soporta cada uno de estos niveles en MySQL 5.0. El nivel por defecto es .

Puede inicializar el nivel de aislamiento global por defecto para mysqld con la opción . Consulte Sección 5.3.1, “Opciones del comando mysqld.