Table Locking
MySQL permite bloquear tablas completas con LOCK TABLES para controlar el acceso concurrente. Esto es diferente de los bloqueos de fila que InnoDB maneja automáticamente.
Sintaxis
-- Bloqueo de lectura (compartido)
LOCK TABLES nombre_tabla READ;
-- Bloqueo de escritura (exclusivo)
LOCK TABLES nombre_tabla WRITE;
-- Bloquear múltiples tablas
LOCK TABLES tabla1 READ, tabla2 WRITE;
-- Desbloquear todas las tablas
UNLOCK TABLES;Bloqueo de lectura (READ)
Un bloqueo READ permite que todas las sesiones lean la tabla, pero nadie puede escribir.
-- Sesión 1: Bloquear para lectura
LOCK TABLES productos READ;
-- Leer funciona normalmente
SELECT COUNT(*) FROM productos;
-- No puedes escribir en la tabla bloqueada
-- INSERT INTO productos (nombre, precio, stock, categoria_id)
-- VALUES ('Test', 10, 1, 1);
-- Error 1099: Table 'productos' was locked with a READ lock
-- Tampoco puedes leer otras tablas (no bloqueadas)
-- SELECT * FROM categorias;
-- Error 1100: Table 'categorias' was not locked with LOCK TABLES
UNLOCK TABLES;Otras sesiones pueden leer la tabla pero si intentan escribir, se bloquean hasta que se libere el bloqueo:
Sesión 1:
LOCK TABLES productos READ;
-- Realizar consultas...Sesión 2:
-- Leer funciona
SELECT * FROM productos WHERE id = 1;
-- Escribir se bloquea (espera)
UPDATE productos SET stock = stock - 1 WHERE id = 1;
-- Esperando...Sesión 1:
UNLOCK TABLES;
-- Ahora el UPDATE de la sesión 2 se ejecutaBloqueo de escritura (WRITE)
Un bloqueo WRITE da acceso exclusivo: solo la sesión que tiene el bloqueo puede leer y escribir.
-- Sesión 1: Bloquear para escritura
LOCK TABLES productos WRITE;
-- Leer y escribir funciona
SELECT COUNT(*) FROM productos;
INSERT INTO productos (nombre, precio, stock, categoria_id)
VALUES ('Lock test', 10.00, 1, 1);
DELETE FROM productos WHERE nombre = 'Lock test';
UNLOCK TABLES;Otras sesiones no pueden ni leer ni escribir:
Sesión 1:
LOCK TABLES productos WRITE;Sesión 2:
-- Ni siquiera la lectura funciona (se bloquea)
SELECT * FROM productos WHERE id = 1;
-- Esperando...Comparación READ vs WRITE
| Característica | READ | WRITE |
|---|---|---|
| Sesión actual: lectura | Sí | Sí |
| Sesión actual: escritura | No | Sí |
| Otras sesiones: lectura | Sí | Bloqueadas |
| Otras sesiones: escritura | Bloqueadas | Bloqueadas |
Bloquear múltiples tablas
Cuando necesitas acceder a varias tablas, debes bloquearlas todas en una sola sentencia:
LOCK TABLES productos READ, categorias READ;
-- Ahora puedes consultar ambas tablas
SELECT p.nombre, c.nombre AS categoria
FROM productos p
JOIN categorias c ON p.categoria_id = c.id;
UNLOCK TABLES;Si usas alias en la consulta, debes declararlos en el bloqueo:
LOCK TABLES productos AS p READ, categorias AS c READ;
SELECT p.nombre, c.nombre
FROM productos AS p
JOIN categorias AS c ON p.categoria_id = c.id;
UNLOCK TABLES;Table locking vs Row locking
| Característica | Table Locking | Row Locking (InnoDB) |
|---|---|---|
| Granularidad | Tabla completa | Filas individuales |
| Concurrencia | Baja | Alta |
| Overhead | Bajo | Mayor |
| Deadlocks | Imposibles | Posibles |
| Motor | Todos | Solo InnoDB |
| Uso con transacciones | No recomendado | Sí |
Bloqueos y transacciones
LOCK TABLES y las transacciones InnoDB no funcionan bien juntos. LOCK TABLES causa un COMMIT implícito:
START TRANSACTION;
INSERT INTO productos (nombre, precio, stock, categoria_id)
VALUES ('Trans Lock', 10.00, 1, 1);
-- LOCK TABLES causa COMMIT implícito del INSERT anterior
LOCK TABLES productos WRITE;
-- No puedes hacer ROLLBACK del INSERT
ROLLBACK; -- No revierte nada
UNLOCK TABLES;DELETE FROM productos WHERE nombre = 'Trans Lock';Para bloqueos a nivel de fila dentro de transacciones, usa SELECT ... FOR UPDATE:
START TRANSACTION;
-- Bloquea solo la fila con id = 1
SELECT * FROM productos WHERE id = 1 FOR UPDATE;
UPDATE productos SET stock = stock - 1 WHERE id = 1;
COMMIT;Caso práctico: exportación consistente
Bloquear tablas para obtener una instantánea consistente durante una exportación:
-- Bloquear todas las tablas necesarias
LOCK TABLES
productos READ,
categorias READ,
pedidos READ,
detalle_pedidos READ;
-- Realizar la exportación
SELECT * FROM productos INTO OUTFILE '/tmp/productos.csv'
FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';
SELECT * FROM pedidos INTO OUTFILE '/tmp/pedidos.csv'
FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';
-- Liberar bloqueos
UNLOCK TABLES;En la práctica, es mejor usar mysqldump --single-transaction para tablas InnoDB.
Caso práctico: mantenimiento de tabla MyISAM
Las tablas MyISAM no soportan transacciones, por lo que LOCK TABLES es la única forma de garantizar consistencia:
-- Crear tabla MyISAM de ejemplo
CREATE TABLE log_accesos (
id INT AUTO_INCREMENT PRIMARY KEY,
pagina VARCHAR(200),
fecha DATETIME DEFAULT NOW()
) ENGINE = MyISAM;
INSERT INTO log_accesos (pagina) VALUES ('/inicio'), ('/productos'), ('/contacto');-- Bloquear para mantenimiento
LOCK TABLES log_accesos WRITE;
-- Archivar y limpiar
CREATE TABLE log_accesos_backup LIKE log_accesos;
INSERT INTO log_accesos_backup SELECT * FROM log_accesos;
DELETE FROM log_accesos;
UNLOCK TABLES;-- Limpieza
DROP TABLE IF EXISTS log_accesos;
DROP TABLE IF EXISTS log_accesos_backup;FLUSH TABLES WITH READ LOCK
Bloquea todas las tablas de todas las bases de datos para lectura. Útil para backups a nivel de sistema de archivos:
-- Bloqueo global de solo lectura
FLUSH TABLES WITH READ LOCK;
-- Realizar backup del sistema de archivos
-- (copia de archivos de datos)
-- Liberar
UNLOCK TABLES;Verificar bloqueos activos
-- Ver bloqueos actuales (MySQL 8.0+)
SELECT * FROM performance_schema.metadata_locks
WHERE OBJECT_TYPE = 'TABLE'
AND LOCK_STATUS = 'GRANTED'\G-- Ver conexiones esperando bloqueos
SHOW PROCESSLIST;Cuándo usar table locking
| Escenario | Recomendación |
|---|---|
| Tablas InnoDB normales | Usar transacciones y bloqueos de fila |
| Tablas MyISAM | Usar LOCK TABLES cuando se necesite consistencia |
| Backup consistente | Usar mysqldump --single-transaction (InnoDB) |
| Mantenimiento masivo | Considerar LOCK TABLES para evitar interferencia |
| Acceso concurrente alto | Preferir bloqueos de fila (InnoDB) |
Resumen
LOCK TABLES READpermite lectura compartida, bloquea escriturasLOCK TABLES WRITEda acceso exclusivo totalUNLOCK TABLESlibera todos los bloqueos- Preferir transacciones InnoDB y
FOR UPDATEsobreLOCK TABLES LOCK TABLEScausaCOMMITimplícito, no mezclar con transacciones
Con esto completamos la sección de transacciones. En la siguiente sección exploraremos las funciones de cadena en MySQL.
Escrito por Eduardo Lázaro
