Escenarios concurrentes
Cuando aprendemos MySQL, a menudo mencionamos las cuatro características de las cosas, atomicidad, consistencia, aislamiento y durabilidad. Entonces, ¿cómo se logra el aislamiento?
La esencia del aislamiento es controlar la concurrencia , si las sentencias SQL se ejecutan en serie. Entonces no habrá concepto de aislamiento en las cuatro características de la base de datos, y no habrá problemas como lecturas sucias, lecturas no repetibles y lecturas fantasma.
Solo hay cuatro tipos de operaciones simultáneas en la base de datos: escritura-escritura, lectura-lectura, lectura-escritura y escritura-lectura.
escribe escribe
Cuando la transacción A actualiza un registro, ¿la transacción B puede actualizar el mismo registro al mismo tiempo?
La respuesta es definitivamente no, de lo contrario causará el problema de la escritura sucia.¿Cómo evitar la escritura sucia? La respuesta es cerrar
leer leer
Las operaciones de lectura de MySQL no están bloqueadas de forma predeterminada, por lo que se pueden leer en paralelo
leer-escribir y escribir-leer
Basado en los diferentes niveles de tolerancia de operaciones concurrentes en varios escenarios, MySQL ha desarrollado un concepto de aislamiento . Puede elegir el nivel de aislamiento según el escenario empresarial.
√ significa que sucederá, × significa que no sucederá
nivel de aislamiento | lectura sucia | lectura no repetible | alucinaciones |
---|---|---|---|
leer sin compromiso | √ | √ | √ |
leer comprometido | × | √ | √ |
lectura repetible | × | × | √ |
serializable (serializable) | × | × | × |
Bloqueos en MySQL
bloqueo de nivel de fila
Hay dos tipos de bloqueos de nivel de fila en el motor de almacenamiento InnoDB:
- Bloqueo compartido (bloqueo compartido, denominado bloqueo S), cuando una transacción necesita leer un registro, primero debe adquirir el bloqueo S para cambiar el registro
- Bloqueo exclusivo (bloqueo exclusivo, denominado bloqueo X), cuando una transacción desea cambiar un registro, primero debe obtener el bloqueo X del registro
Si la transacción T1 adquiere el bloqueo S de un registro, la transacción T2 también accede a este registro. Si la transacción T2 quiere adquirir el bloqueo S de este registro nuevamente, puede tener éxito. Esta situación se denomina compatibilidad de bloqueo. Si la transacción T2 desea adquirir el bloqueo X de este registro nuevamente, esta operación se bloqueará hasta que la transacción T1 confirme el S bloquear liberar
Si la transacción T1 adquiere el bloqueo X de un registro, entonces, ya sea que la transacción T2 quiera adquirir el bloqueo S o el bloqueo X del registro a continuación, se bloqueará hasta que se confirme la transacción 1, lo que se denomina incompatibilidad de bloqueo.
Varias transacciones pueden leer registros al mismo tiempo, es decir, los bloqueos compartidos no se excluyen mutuamente, pero los bloqueos compartidos bloquean los bloqueos exclusivos. Exclusión mutua entre bloqueos exclusivos
La relación de compatibilidad entre S lock y X lock es la siguiente
compatibilidad | Bloqueo X | Bloqueo S |
---|---|---|
Bloqueo X | mutuamente excluyentes | mutuamente excluyentes |
Bloqueo S | mutuamente excluyentes | compatible |
actualizar, eliminar e insertar agregará automáticamente bloqueos exclusivos a los datos involucrados, y la declaración de selección no agregará ningún bloqueo de forma predeterminada.
¿En qué circunstancias se bloqueará la operación de lectura?
- seleccione... bloquear en modo compartido, agregue S lock a los registros de lectura
- seleccione ... para actualizar, agregue bloqueo X a los registros de lectura
- Lea registros en una transacción, agregue S lock a los registros de lectura
- El nivel de aislamiento de la transacción está por debajo de SERIALIZABLE y el bloqueo S se aplica a los registros de lectura
Hay tres algoritmos para bloqueos de fila en InnoDB:
- Bloqueo de registro: bloquear un solo registro
- Gap Lock: Gap lock, bloquea el espacio frente al registro y no permite que se inserten registros
- Bloqueo de tecla siguiente: bloquee los datos y el espacio frente a los datos al mismo tiempo, es decir, ni los datos ni el espacio frente a los datos pueden insertar registros
Escriba una demostración para demostrar
CREATE TABLE `girl` (
`id` int(11) NOT NULL,
`name` varchar(255),
`age` int(11),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into girl values
(1, '西施', 20),
(5, '王昭君', 23),
(8, '貂蝉', 25),
(10, '杨玉环', 26),
(12, '陈圆圆', 20);
Bloqueo de registro
bloquear un solo registro
Por ejemplo, agregue un bloqueo de registro a los datos con un valor de identificación de 8, el diagrama esquemático es el siguiente
Record Lock también se divide en S lock y X lock, y la compatibilidad es la misma que se describió anteriormente.
El tipo de bloqueo que se agrega a la ejecución de SQL está restringido por muchas condiciones, como el nivel de aislamiento de la transacción y el índice utilizado durante la ejecución (como índice agrupado, índice no agrupado, etc.), por lo que no se analizará. en detalle, pero se darán algunos ejemplos simples.
-- READ UNCOMMITTED/READ COMMITTED/REPEATABLE READ 利用主键进行等值查询
-- 对id=8的记录加S型Record Lock
select * from girl where id = 8 lock in share mode;
-- READ UNCOMMITTED/READ COMMITTED/REPEATABLE READ 利用主键进行等值查询
-- 对id=8的记录加X型Record Lock
select * from girl where id = 8 for update;
Bloqueo de espacio
Bloquea el espacio frente al registro y no permite insertar registros
MySQL puede resolver el problema de lectura fantasma a través de MVCC y bloqueo bajo el nivel de aislamiento de lectura repetible
Lectura actual: Lectura de
instantánea bloqueada: MVCC
Pero, ¿cómo bloquearlo? Debido a que estos registros fantasma no existen cuando se realiza la operación de lectura por primera vez, no tenemos forma de agregar Record Lock. En este momento, se puede resolver agregando Gap Lock, es decir, bloqueando el espacio.
Por ejemplo, si una transacción agrega un bloqueo de espacio al registro con id=8, significa que otras transacciones no pueden insertar nuevos registros en el espacio antes del registro con id=8, es decir, el registro con el valor de id. en el intervalo (5, 8) no está permitido Permite la inserción inmediata. Los registros con valores de identificación en el intervalo (5, 8) no se pueden enviar hasta que se confirme la transacción con el bloqueo de espacio
Veamos el siguiente proceso de bloqueo de SQL
-- REPEATABLE READ 利用主键进行等值查询
-- 但是主键值并不存在
-- 对id=8的聚集索引记录加Gap Lock
SELECT * FROM girl WHERE id = 7 LOCK IN SHARE MODE;
Dado que el registro con id=7 no existe, para evitar el fenómeno de lectura fantasma (para evitar el registro con id=7 en el conjunto de resultados obtenido al ejecutar la misma declaración bajo la misma transacción), debemos evitar otras transacciones de insertar el id antes de que se confirme la transacción actual = 7 registros, en este momento, puede agregar un Gap Lock a los registros con id = 8, es decir, otras transacciones no pueden insertar nuevos registros con valores de id en el intervalo (5, 8).
Déjame hacerte una pregunta, Gap Lock solo puede bloquear el espacio frente al registro, entonces, ¿cómo bloquear el espacio detrás del último registro?
De hecho, los datos mysql se almacenan en páginas, y cada página tiene 2 pseudo registros
- Registro mínimo, que representa el registro más pequeño de la página.
- registro upremum, que representa el registro más grande de la página
Para evitar que otras transacciones inserten registros cuyo valor de id esté en el rango de (12, +∞), podemos agregar un bloqueo de brecha al registro Supremum de la página donde se encuentra el registro id = 12. En este momento, se puede evitar que otras transacciones inserten el valor de id en (12), +∞) un nuevo registro para este intervalo
Bloqueo de tecla siguiente
Al mismo tiempo, bloquee los datos y el espacio frente a los datos, es decir, los datos y el espacio frente a los datos no pueden insertar registros
, para que pueda entender Siguiente-tecla Bloqueo = Registro Bloqueo + Espacio Cerrar con llave
-- REPEATABLE READ 利用主键进行范围查询
-- 对id=8的聚集索引记录加S型Record Lock
-- 对id>8的所有聚集索引记录加S型Next-key Lock(包括Supremum伪记录)
SELECT * FROM girl WHERE id >= 8 LOCK IN SHARE MODE;
Porque para resolver el problema de la lectura fantasma, es necesario prohibir que otras transacciones inserten registros con id>=8, por lo que
- Agregue bloqueo de registro tipo S al registro de índice agrupado con id = 8
- Agregar bloqueo de tecla siguiente tipo S a todos los registros de índice agrupados con id>8 (incluidos los pseudorregistros supremos)
Con el fin de darle una mejor comprensión
bloqueo de nivel de mesa
Los bloqueos de mesa también se dividen en bloqueos S y bloqueos X.
Al ejecutar instrucciones de selección, inserción, actualización y eliminación en una tabla, el motor de almacenamiento de innodb no agregará bloqueos S o bloqueos X a nivel de tabla a la tabla.
Cuando se ejecutan algunas declaraciones DDL como ALTER TABLE y DROP TABLE en una tabla, se agregarán bloqueos X a la tabla, por lo que otras transacciones se bloquearán al ejecutar declaraciones como SELECT INSERT UPDATE DELETE en esta tabla
Cuando la variable de sistema autocommit=0 e innodb_table_locks=1, para obtener manualmente el bloqueo S o el bloqueo X de la tabla t proporcionada por el motor de almacenamiento InnoDB, puede escribir esto
Agregue un bloqueo S de nivel de tabla a la tabla t
lock tables t read
Agregue un bloqueo X de nivel de tabla a la tabla t
lock tables t write
Si una transacción agrega un bloqueo S a una tabla, entonces
- Otras transacciones pueden continuar adquiriendo el bloqueo S en la mesa
- Otras transacciones pueden continuar adquiriendo bloqueos S en ciertos registros de la tabla
- Otras transacciones no pueden continuar adquiriendo bloqueos X en la mesa
- Otras transacciones no pueden continuar adquiriendo bloqueos X en algunos registros de la tabla
Si una transacción agrega bloqueos X a la tabla, entonces
- Otras transacciones no pueden continuar adquiriendo el bloqueo S en la mesa
- Otras transacciones no pueden continuar obteniendo bloqueos S para algunos registros en la tabla
- Otras transacciones no pueden continuar adquiriendo bloqueos X en la mesa
- Otras transacciones no pueden continuar adquiriendo bloqueos X en algunos registros de la tabla
Por lo tanto, debe tener cuidado al modificar tablas en línea, porque se bloquearán una gran cantidad de transacciones.En la actualidad, existen muchos métodos maduros para modificar tablas en línea, por lo que no los repetiré.
También hay bloqueos IS (bloqueos compartidos previstos) y bloqueos IX (bloqueos exclusivos previstos) a nivel de tabla.
Cuando una cosa pone un bloqueo S en un registro, también pone un bloqueo IS en la tabla correspondiente al registro (el bloqueo IS es un bloqueo a nivel de tabla).Cuando una cosa pone un bloqueo X en un registro, también pone un Bloqueo IX en la tabla correspondiente al registro (bloqueo IX). El bloqueo es un bloqueo a nivel de tabla)
Implementación del nivel de aislamiento de transacciones
RR | RC | |
---|---|---|
selección normal | MVCC | MVCC |
Bloqueado seleccionar y actualizar seleccionar... en modo nítido seleccionar... para actualizar insertar borrar actualizar |
Bloqueo de registro Bloqueo de espacio Bloqueo de tecla siguiente |
Bloqueo de registro * |
Blog de referencia
[1] https://souche.yuque.com/bggh1p/8961260/gyzlaf
[2] https://zhuanlan.zhihu.com/p/35477890
Clasificación de varios bloqueos
[3] https://www.hacker66.me /detalle/ZYXWPXH.html