Fundamentos de transacciones en MySQL: guía completa ACID, aislamiento y autocommit

Última actualización: 11/05/2025
  • InnoDB ofrece transacciones ACID, bloqueo por fila y REPEATABLE READ por defecto.
  • Controla autocommit, START TRANSACTION, COMMIT/ROLLBACK y SAVEPOINT para atomicidad real.
  • Ajusta niveles de aislamiento y modos READ ONLY/READ WRITE con SET TRANSACTION.
  • Evita sucias, no repetibles y fantasmas equilibrando consistencia y rendimiento.

transacciones mysql

Las transacciones en MySQL son el pilar para operar con datos de forma segura cuando intervienen varias sentencias que deben comportarse como una sola unidad. Si algo falla por el camino, queremos volver al estado anterior sin dejar la base de datos a medias. En este artículo vas a encontrar una explicación completa y práctica de cómo funcionan, qué propiedades cumplen y cómo configurarlas para equilibrar consistencia y rendimiento.

Además de cubrir comandos básicos como START TRANSACTION, COMMIT y ROLLBACK, veremos el papel de autocommit, los niveles de aislamiento ACID, bloqueos, savepoints, modos de acceso y SET TRANSACTION. También incluimos ejemplos paso a paso de problemas de concurrencia típicos, notas sobre InnoDB vs MyISAM, cómo manejar transacciones desde PHP (mysqli) y en procedimientos almacenados, así como una batería de casos prácticos para que puedas afianzar lo aprendido. Si estás preparando DAW, DAM o ASIR, estos apuntes te van a venir como anillo al dedo.

Apuntes de BD para DAW, DAM y ASIR — Curso 2025/2026. Este material sintetiza las mejores prácticas y la teoría clave que necesitas dominar para trabajar con transacciones en MySQL de forma profesional.

Nota: El dinero donado nos sirve para mantener nuestro sitio web, así como para generar mejor contenido. Tu apoyo nos ayuda a seguir creando guías técnicas útiles y al día.

Qué es una transacción y por qué importa

Una transacción es una unidad lógica de trabajo que agrupa varias sentencias de forma que o se aplican todas o no se aplica ninguna. Esto evita estados inconsistentes, especialmente en operaciones compuestas que tocan varias tablas o filas. Piensa en un traspaso entre cuentas bancarias: se descuenta de la cuenta origen y se abona en la destino; si una de las acciones falla, no puedes permitir que la otra quede confirmada sola.

MySQL, con el motor InnoDB, implementa transacciones según el modelo ACID, proporcionando garantías sólidas de integridad incluso ante fallos de sistema o cortes de luz. Si vienes de otros SGBD, te sentirás como en casa: los conceptos clave son los mismos.

Propiedades ACID: las cuatro garantías

  • Atomicidad: el bloque se trata como indivisible; o todo OK o nada. Si una operación falla, se revierte todo el conjunto.
  • Consistencia: cada transacción lleva la base de datos de un estado válido a otro. No deja reglas de negocio vulneradas ni datos imposibles.
  • Aislamiento: lo que ocurre dentro de una transacción no debe interferir ni verse afectado por otras que se ejecutan en paralelo, según el nivel elegido.
  • Durabilidad: una vez haces COMMIT, los cambios quedan persistidos incluso ante fallos.

InnoDB vs MyISAM: el motor sí importa

En MySQL existen varios motores de almacenamiento. Solo InnoDB soporta transacciones y claves foráneas; además ofrece bloqueo a nivel de fila y recuperación ante fallos. MyISAM no soporta transacciones y prioriza velocidad sobre consistencia, lo que es útil para ciertos escenarios de lectura intensiva, pero no es adecuado cuando necesitas ACID.

Autocommit: qué es y cómo te afecta

MySQL tiene el modo autocommit activado por defecto. Esto significa que, fuera de una transacción explícita, cada sentencia DML se confirma automáticamente como si estuviese envuelta por START TRANSACTION y COMMIT. Si la sentencia falla, se revierte automáticamente ese intento, pero si tiene éxito, no podrás deshacerla manualmente con ROLLBACK.

Cuando inicias una transacción con START TRANSACTION, MySQL desactiva temporalmente el autocommit hasta que haces COMMIT o ROLLBACK. Puedes cambiar el autocommit a nivel de sesión con SET:

-- Ver el valor actual
SELECT @@autocommit;

-- Desactivar autocommit en la sesión actual
SET autocommit = 0;

-- Activarlo de nuevo
SET autocommit = 1;

Tras desactivar autocommit, los cambios no son permanentes hasta que ejecutes COMMIT; si quieres descartarlos, usa ROLLBACK. Ten en cuenta que esta configuración es por sesión y se resetea al cerrar la conexión.

Comandos básicos: START TRANSACTION, COMMIT y ROLLBACK

El ciclo típico es: iniciar transacción, ejecutar operaciones DML y confirmar o deshacer según el resultado. Tienes sinónimos como BEGIN o BEGIN WORK para iniciar, y COMMIT/ROLLBACK para finalizar:

START TRANSACTION;
  UPDATE cuentas SET saldo = saldo - 100 WHERE id = 20;
  UPDATE cuentas SET saldo = saldo + 100 WHERE id = 30;
COMMIT; -- o ROLLBACK si algo fue mal

Si el sistema cae entre las dos UPDATE o se pierde la conexión con autocommit desactivado, InnoDB garantiza que la transacción incompleta no se confirmará. Si una de las cuentas no existe o una restricción (p. ej., CHECK de saldo no negativo) falla, la transacción se revierte y la base queda como al principio.

Savepoints: control fino dentro de la transacción

Con SAVEPOINT creas puntos de recuperación dentro de una transacción para poder deshacer parcialmente sin tirar todo el trabajo:

START TRANSACTION;
  UPDATE productos SET stock = stock - 2 WHERE id = 10;
  SAVEPOINT p1;
  UPDATE productos SET stock = stock - 5 WHERE id = 11;
  -- Si falla lo siguiente, solo deshacemos hasta p1
  ROLLBACK TO SAVEPOINT p1;
  -- Seguimos con otras operaciones
RELEASE SAVEPOINT p1;
COMMIT;

Si defines varios SAVEPOINT con el mismo nombre, MySQL considera el último. También puedes eliminarlos con RELEASE SAVEPOINT para mantener limpia la transacción.

Niveles de aislamiento: equilibrio entre consistencia y rendimiento

El valor por defecto en MySQL es REPEATABLE READ, que ofrece lecturas coherentes dentro de la misma transacción gracias al multiversioning (MVCC).

Problemas clásicos de concurrencia que queremos acotar:

  • Lectura sucia (Dirty Read): leer cambios de otra transacción que aún no ha hecho COMMIT.
  • Lectura no repetible: leer la misma fila dos veces y obtener valores distintos por actualizaciones confirmadas de otra transacción entre ambas lecturas.
  • Lectura fantasma: ejecutar la misma consulta y que aparezcan filas nuevas debido a inserciones confirmadas por otra transacción.

Comportamiento por nivel (resumen práctico): READ UNCOMMITTED permite las tres anomalías; READ COMMITTED evita lecturas sucias pero puede sufrir no repetibles y fantasmas; REPEATABLE READ evita sucias y no repetibles y, en general, solo admite potenciales “fantasmas”; SERIALIZABLE bloquea como si ejecutaras en serie, eliminando las tres a costa de más bloqueos.

-- Consultar nivel de aislamiento (sesión y global)
SELECT @@transaction_isolation;     -- sesión
SELECT @@global.transaction_isolation; -- global

Puedes ajustar el aislamiento por transacción, sesión o globalmente. Recuerda que los cambios GLOBAL afectan a nuevas conexiones, no a las existentes.

Bloqueos y lecturas con bloqueo

Para mantener el aislamiento, el motor usa bloqueos (locking). InnoDB bloquea por defecto a nivel de fila, lo que permite mayor concurrencia que el bloqueo por tabla. Un bloqueo impide que otras transacciones vean o alteren datos en uso mientras la tuya no haya finalizado.

Según el nivel y la operación, MySQL puede requerir bloqueos de lectura o escritura. Por ejemplo, SERIALIZABLE con autocommit desactivado convierte lecturas en bloqueantes para reforzar la consistencia. El objetivo es evitar que otra transacción interfiera con tu “instantánea” de datos.

Modos de acceso: READ WRITE y READ ONLY

Las transacciones pueden declararse en modo READ WRITE (por defecto) o READ ONLY. En modo solo lectura, no se permiten cambios sobre tablas, útil para informes reproducibles y estables.

-- Establecer modo de acceso al iniciar
START TRANSACTION READ ONLY;
-- o
START TRANSACTION READ WRITE;

También puedes fijarlo con SET TRANSACTION, combinándolo con el nivel de aislamiento y el ámbito de aplicación.

SET TRANSACTION: aislamiento, acceso y ámbitos (SESSION, GLOBAL)

La sentencia SET TRANSACTION permite establecer el nivel de aislamiento y el modo de acceso para la próxima transacción, para toda la sesión o de manera global:

-- Aplica a la próxima transacción (si no indicas ámbito)
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ, READ ONLY;

-- Aplica a todas las transacciones de esta sesión actual
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ WRITE;

-- Aplica a sesiones futuras (no a las existentes)
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

Este control fino te permite equilibrar fiabilidad y rendimiento según el caso de uso, desde cargas analíticas a alta concurrencia OLTP.

Ejemplos de concurrencia: Dirty Read, No Repetible y Fantasma

Dirty Read (lectura sucia): una transacción B lee valores no confirmados por A. Con READ UNCOMMITTED esto es posible; con READ COMMITTED en adelante, no.

-- Terminal A
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
UPDATE cuentas SET saldo = saldo - 100 WHERE id = 1;
-- (sin COMMIT todavía)

-- Terminal B
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT saldo FROM cuentas WHERE id = 1; -- puede ver el saldo "sucio"

-- Terminal A
ROLLBACK; -- los cambios se deshacen

Lectura no repetible: B confirma un UPDATE entre dos lecturas de A. Con REPEATABLE READ lo evitas; con READ COMMITTED puede ocurrir.

-- Terminal A
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
SELECT saldo FROM cuentas WHERE id = 1; -- lectura 1

-- Terminal B (otra sesión)
UPDATE cuentas SET saldo = saldo - 100 WHERE id = 1;
COMMIT;

-- Terminal A
SELECT saldo FROM cuentas WHERE id = 1; -- lectura 2 (puede diferir)
ROLLBACK;

Lectura fantasma: entre dos consultas que agregan datos, otra transacción inserta filas que encajan en el filtro. Con SERIALIZABLE se evita a costa de más bloqueos.

-- Terminal A
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT SUM(saldo) FROM cuentas;

-- Terminal B
INSERT INTO cuentas(id, saldo) VALUES (4, 3000);
COMMIT;

-- Terminal A
SELECT SUM(saldo) FROM cuentas; -- puede observar un "fantasma"
ROLLBACK;

DML esencial y claves foráneas: efectos ON DELETE / ON UPDATE

El DML agrupa SELECT, INSERT, UPDATE y DELETE. Al definir claves foráneas en InnoDB, puedes fijar el comportamiento ante borrados/actualizaciones en la tabla referenciada:

  • RESTRICT: impide eliminar/actualizar si hay referencias. Es el valor por defecto en MySQL.
  • CASCADE: propaga la acción a las filas hijas.
  • SET NULL: pone el valor a NULL en las filas hijas.
  • NO ACTION: equivalente a RESTRICT en MySQL.
  • SET DEFAULT: no está disponible con InnoDB en MySQL.

Estas reglas son clave para asegurar consistencia referencial y evitar datos huérfanos cuando trabajas con transacciones y relaciones complejas.

Transacciones desde PHP (mysqli): autocommit, commit y rollback

Si programas en PHP con mysqli, puedes controlar transacciones de forma sencilla. Desactiva autocommit, ejecuta tus consultas y confirma o revierte según el resultado:

$db = new mysqli("localhost", "root", "pass", "database");
$db->autocommit(false);

try {
  $db->query("INSERT INTO users (name) VALUES ('marcus')");
  $db->query("UPDATE users SET name = 'jane' WHERE id = 39");
  $db->commit();
} catch (Throwable $e) {
  $db->rollback();
  // log del error
}

Con este patrón, si cualquier sentencia falla, haces rollback() y evitas inconsistencias. Luego ya decides si reintentas, notificas o tomas otra acción.

Procedimientos almacenados y manejo de errores en MySQL

En procedimientos almacenados de MySQL puedes declarar manejadores de errores para SQLEXCEPTION y SQLWARNING, de modo que ejecutes ROLLBACK automáticamente ante fallos:

DELIMITER //
CREATE PROCEDURE transferir(IN p_origen INT, IN p_destino INT, IN p_importe DECIMAL(10,2))
BEGIN
  DECLARE exit handler FOR SQLEXCEPTION
  BEGIN
    ROLLBACK;
  END;

  START TRANSACTION;
    UPDATE cuentas SET saldo = saldo - p_importe WHERE id = p_origen;
    UPDATE cuentas SET saldo = saldo + p_importe WHERE id = p_destino;
  COMMIT;
END //
DELIMITER ;

También puedes usar un único manejador común para diferentes tipos de error si te encaja mejor. El objetivo es centralizar la reversión y dejar la base limpia cuando algo no va bien.

Casos prácticos propuestos: pon a prueba lo aprendido

Tienda de informática

  • Inserta fabricantes indicando código y nombre; y también solo con nombre.
  • Inserta productos asociados a fabricantes con diferentes conjuntos de columnas (con y sin código).
  • Crea la tabla fabricante_productos con columnas nombre_fabricante, nombre_producto, precio e inserta de una sola vez todos los registros desde tienda.
  • Crea la vista vista_fabricante_productos con las tres columnas anteriores.
  • Elimina fabricantes como Asus o Xiaomi y razona por qué puede no ser posible; ajusta claves foráneas (p. ej., ON DELETE) si hace falta.
  • Actualiza códigos de fabricantes (Lenovo a 20, Huawei a 30) y analiza las restricciones referenciales necesarias.
  • Actualiza precios sumando 5 € a todos los productos; elimina impresoras con precio < 200 €.

Empleados

  • Inserta departamentos con diferentes combinaciones de columnas (con y sin código, con gastos).
  • Inserta empleados vinculados a departamentos (con y sin código explícito).
  • Crea y rellena departamento_backup a partir de departamento.
  • Elimina departamentos (Proyectos, Desarrollo) y justifica si se puede o no; ajusta foráneas de ser necesario.
  • Actualiza códigos (p. ej., Recursos Humanos a 30; Publicidad a 40) evaluando impacto referencial.
  • Incrementa presupuestos +50.000 € solo para los < 20.000 €.
  • Transacción: elimina empleados sin departamento asociado garantizando consistencia.

Jardinería

  • Inserta oficina en Almería y un empleado representante de ventas.
  • Inserta cliente cuyo comercial sea el empleado anterior; crea un pedido con al menos dos productos.
  • Actualiza el código del cliente y verifica cambios en tablas relacionadas; bórralo y revisa efectos; si no hay cascadas, configura ON DELETE CASCADE.
  • Elimina clientes sin pedidos; sube un 20% el precio de productos sin pedidos; borra pagos del cliente con menor límite de crédito.
  • Ajusta límite de crédito a 0 para el cliente con menos unidades del producto 11679.
  • Modifica la tabla detalle_pedido añadiendo campo iva; mediante una transacción pon 18 a pedidos desde enero 2009 y 21 al resto.
  • Añade campo total_linea y calcula con precio_unidad*cantidad*(1 + (iva/100)) para todos los registros.
  • Borra el cliente con menor límite de crédito: evalúa si se puede con una sola consulta y por qué.
  • Inserta oficina en Granada con tres comerciales y tres clientes asociados; transacción para un pedido por cliente con dos productos cada uno; borra un cliente y ajusta foráneas si no hay cascada; transacción para registrar pagos de esos pedidos.

Ensayo adicional útil: simula una pérdida de conexión con SET AUTOCOMMIT = 0, cierra la sesión antes de finalizar y luego reconecta para comprobar qué quedó persistido y qué no. Esto te aterriza el concepto de durabilidad y atomicidad.

Comparativa rápida con SQL Server y Oracle

Los conceptos son homólogos: BEGIN/START TRANSACTION, COMMIT, ROLLBACK y niveles de aislamiento. En SQL Server existen además niveles como SNAPSHOT, que presenta una vista consistente al inicio de la transacción sin bloquear tanto como SERIALIZABLE. Oracle ofrece un conjunto similar de niveles; en la práctica, cambia el “dialecto” pero la música es la misma: se busca el punto óptimo entre aislamiento y rendimiento.

Preguntas típicas de examen/entrevista

  • ¿Qué son las propiedades ACID? Defínelas y pon un ejemplo.
  • ¿Cuáles son los tres problemas de concurrencia y cómo mitigarlos con niveles de aislamiento?
  • ¿Cuál es el nivel por defecto en InnoDB? REPEATABLE READ.
  • ¿Se pueden hacer transacciones con MyISAM? No, necesitas InnoDB.
  • Diferencias InnoDB vs MyISAM: transacciones, foráneas, bloqueo por fila, recuperación, etc.
  • Transferencias bancarias: ¿qué pasa si falla una UPDATE intermedia o si la cuenta no existe? Respuesta: rollback asegura consistencia.

Dominar transacciones en MySQL es entender cómo se combinan ACID, autocommit, aislamiento, bloqueos, savepoints y modos de acceso para proteger tus datos sin estrangular el rendimiento. Con InnoDB, tienes las herramientas para que operaciones complejas (pagos, pedidos, inventario) se comporten como una sola acción segura. Ajusta SET TRANSACTION al caso de uso, apóyate en procedimientos y control de errores, y practica con los casos propuestos: el salto de calidad en tus sistemas se nota enseguida.

visión general de sistemas de almacenamiento de datos
Artículo relacionado:
Visión general de sistemas de almacenamiento de datos
Related posts: