MySQL Insert deadlock

insertar punto muerto

inserte el paso de bloqueo

El proceso general de bloqueo de instrucciones de inserción es el siguiente:

1. Solicite el "Bloqueo de inserción intencional" en el espacio donde se encuentra la fila. 2. Solicite el "bloqueo exclusivo" de la fila que se va a insertar. 3. Si el conflicto de clave única se desencadena en el segundo paso, entonces la transacción que entró en conflicto debe dividir el proceso de bloqueo en dos pasos, primero solicitar el "bloqueo compartido" de la fila y luego solicitar el "bloqueo exclusivo", si existe Si varias cosas entran en conflicto, todas deben solicitar un "bloqueo compartido" y luego esperar el uno al otro (punto muerto) al solicitar bloqueos exclusivos. En este momento, MySQL elegirá sacrificar algunas de estas transacciones y dejar que una de ellas se complete.


Reproduzca el punto muerto de inserción

Reproduzca la escena del punto muerto de inserción paso a paso según la teoría.

Sesión uno Sesión dos Sesión tres
crear tabla t (x clave primaria int);    
iniciar transacción;    
insertar en t (x) valores (1024);    
  insertar en t (x) valores (1024); insertar en t (x) valores (1024);
Retroceder comprometerse con éxito ERROR 1213 (40001): se encontró un punto muerto al intentar bloquear; intente reiniciar la transacción

show engine innodb status La información sobre el punto muerto en la salida es la siguiente.

------------------------
LATEST DETECTED DEADLOCK
------------------------
2019-09-03 19:29:30 0x7f9ab00b4700
*** (1) TRANSACTION:
TRANSACTION 2759830, ACTIVE 9 sec inserting
mysql tables in use 1, locked 1 LOCK WAIT 4 lock struct(s), heap size 1136, 2 row lock(s) MySQL thread id 13, OS thread handle 140302402717440, query id 1221 127.0.0.1 root update insert into t(x) values(1024) *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 16 page no 4 n bits 72 index PRIMARY of table `tempdb`.`t` trx id 2759830 lock_mode X insert intention waiting Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;; *** (2) TRANSACTION: TRANSACTION 2759831, ACTIVE 6 sec inserting mysql tables in use 1, locked 1 4 lock struct(s), heap size 1136, 2 row lock(s) MySQL thread id 14, OS thread handle 140302355220224, query id 1222 127.0.0.1 root update insert into t(x) values(1024) *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 16 page no 4 n bits 72 index PRIMARY of table `tempdb`.`t` trx id 2759831 lock mode S Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;; *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 16 page no 4 n bits 72 index PRIMARY of table `tempdb`.`t` trx id 2759831 lock_mode X insert intention waiting Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;; *** WE ROLL BACK TRANSACTION (2) 

¿Por qué MySQL hace esto?

La premisa es que si dos transacciones insertan el mismo registro, una de ellas debe fallar. Un punto muerto también debe tener una falla, entonces ¿por qué no incorporar la inserción concurrente en el flujo de procesamiento del punto muerto? Cuando lo pienso, necesito hacerlo. Necesito eliminar el proceso de bloqueo ascendente, primero poner el "bloqueo compartido S" y luego el "bloqueo exclusivo X". Dado que la "S" se puede compartir, ambos pueden completar este paso. X "para que las dos transacciones se esperen (punto muerto).


Solución

Si realmente encuentra el escenario anterior en los negocios, MySQL está estancado. No quieres dejarlo en punto muerto, entonces, ¿qué debes hacer? ¿MySQL no desarmó los pasos de bloqueo? Luego lo armamos.

select ... for update Directamente en el bloqueo exclusivo de línea, a través del cual podemos combinar los dos pasos separados, on duplicate key update cuando se encuentran conflictos, se actualizarán directamente y no se informará ningún error; la combinación de estos dos códigos de artefactos se puede cambiar a la siguiente forma.

Sesión uno Sesión dos Sesión tres
crear tabla t (x clave primaria int);    
iniciar transacción;    
seleccione x de t para la actualización; insertar en los valores t (x) (1024) en la actualización de clave duplicada x = 1024;    
  seleccione x de t para la actualización; insertar en los valores t (x) (1024) en la actualización de clave duplicada x = 1024; seleccione x de t para la actualización; insertar en los valores t (x) (1024) en la actualización de clave duplicada x = 1024;
Retroceder comprometerse con éxito comprometerse con éxito

Efectos secundarios

Debido a que  select for update es un bloqueo exclusivo, habrá algunos problemas en la concurrencia, se recomienda read-committedusar juntos.


Huevos de pascua

Según el análisis, podemos saber que el problema ocurre en el bloqueo de la fila. El ajuste del nivel de aislamiento  READ-COMMITTED solo afectará al  gap bloqueo. Pensé que no habrá más bloqueos intencionales (un espacio especial) en este nivel de aislamiento.

mysql> show variables like '%iso%';
+-----------------------+----------------+ | Variable_name | Value | +-----------------------+----------------+ | transaction_isolation | READ-COMMITTED | +-----------------------+----------------+ 1 row in set (0.00 sec) 

Haz lo mismo.

Sesión uno Sesión dos Sesión tres
crear tabla t (x clave primaria int);    
iniciar transacción;    
insertar en t (x) valores (1024);    
  insertar en t (x) valores (1024); insertar en t (x) valores (1024);
Retroceder comprometerse con éxito ERROR 1213 (40001): se encontró un punto muerto al intentar bloquear; intente reiniciar la transacción

------------------------
LATEST DETECTED DEADLOCK
------------------------
2020-04-11 13:57:15 0x7ff1bccf1700
*** (1) TRANSACTION:
TRANSACTION 6946, ACTIVE 12 sec inserting
mysql tables in use 1, locked 1 LOCK WAIT 4 lock struct(s), heap size 1136, 2 row lock(s) MySQL thread id 9, OS thread handle 140676621076224, query id 237 127.0.0.1 root update insert into t(x) values(1024) *** (1) HOLDS THE LOCK(S): RECORD LOCKS space id 5 page no 4 n bits 72 index PRIMARY of table `tempdb`.`t` trx id 6946 lock mode S Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;; *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 5 page no 4 n bits 72 index PRIMARY of table `tempdb`.`t` trx id 6946 lock_mode X insert intention waiting Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;; *** (2) TRANSACTION: TRANSACTION 6947, ACTIVE 9 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 4 lock struct(s), heap size 1136, 2 row lock(s) MySQL thread id 13, OS thread handle 140676151592704, query id 258 127.0.0.1 root update insert into t(x) values(1024) *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 5 page no 4 n bits 72 index PRIMARY of table `tempdb`.`t` trx id 6947 lock mode S Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;; *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 5 page no 4 n bits 72 index PRIMARY of table `tempdb`.`t` trx id 6947 lock_mode X insert intention waiting Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;; *** WE ROLL BACK TRANSACTION (2) 

READ-COMMITTED No hay gap bloqueo bajo el nivel de aislamiento  , pero el documento oficial dice que  insert intention es una especie de brecha, por lo  insert intention que no debería existir.

Supongo que te gusta

Origin www.cnblogs.com/JiangLe/p/12680228.html
Recomendado
Clasificación