Análisis de simulación de punto muerto de MySQL

Un punto muerto es una situación en la que diferentes transacciones no pueden continuar porque cada transacción tiene un bloqueo que la otra necesita. Debido a que ambas transacciones están esperando que el recurso esté disponible, ninguna liberará el bloqueo que contiene. Este artículo registra las causas de los interbloqueos y sus soluciones.

1. Conocimientos preliminares

1.1 Bloqueos de mesa y bloqueos de fila

  • cerradura de mesa

Los candados de mesa son MySQLla estrategia de bloqueo más básica y la menos costosa. El bloqueo de la tabla bloqueará toda la tabla de datos. Antes de que el usuario escriba (insertar/eliminar/actualizar), necesita obtener un bloqueo de escritura (los bloqueos de escritura se bloquearán entre sí); cuando no hay un bloqueo de escritura, el usuario que lee puede obtener un bloqueo de lectura (el bloqueo de lectura no se bloqueará entre sí).

  • Bloqueos de fila (solo para InnoDB)

Los bloqueos a nivel de fila pueden admitir el procesamiento concurrente en la mayor medida (pero también generan la mayor sobrecarga de bloqueo). Los bloqueos a nivel de fila solo se implementan en el motor de almacenamiento, pero MySQLno en la capa del servidor. La capa del servidor no tiene conocimiento de la implementación específica en el motor de almacenamiento.

1.2 Introducción al bloqueo de filas

1.2.1 Candados compartidos y candados exclusivos

InnoDBImplementa el bloqueo estándar a nivel de fila, de los cuales existen dos tipos de bloqueos, Sbloqueos compartidos ( ) y bloqueos exclusivos ( X).

  • Un bloqueo compartido ( S) permite que la transacción que contiene el bloqueo lea una fila.

  • Un Xbloqueo exclusivo ( ) permite que la transacción que mantiene el bloqueo actualice o elimine una fila.

1.2.2 Bloqueo de intención

InnoDBAdmite bloqueo de granularidad múltiple, lo que permite que coexistan bloqueos de fila y bloqueos de tabla. LOCK TABLES ... WRITEPor ejemplo, una declaración como esta adquiere un bloqueo exclusivo (un candado) en la tabla especificada . X Para que el bloqueo en múltiples niveles de granularidad sea práctico, InnoDButilice bloqueos de intención. Los bloqueos de intención son bloqueos a nivel de tabla que indican qué tipo de bloqueo (compartido o exclusivo) necesita una transacción más adelante en una fila de una tabla. Hay dos tipos de bloqueos por intención:

  • Los bloqueos compartidos de intención ( IS) indican que la transacción tiene la intención de establecer bloqueos compartidos en filas individuales de la tabla.

  • Un bloqueo exclusivo de intención ( IX) indica que la transacción tiene la intención de establecer un bloqueo exclusivo en cada fila de la tabla.

El ejemplo SELECT ... LOCK IN SHARE MODEestablece un IScandado y SELECT ... FOR UPDATEestablece un IXcandado.

El protocolo de bloqueo de intención es el siguiente:

  • Antes de que una transacción pueda adquirir bloqueos compartidos en las filas de una tabla, primero debe adquirir ISun bloqueo en la tabla o un bloqueo más fuerte.

  • Antes de que una transacción pueda adquirir bloqueos exclusivos en las filas de una tabla, primero debe adquirir IXun bloqueo en la tabla.

La siguiente matriz resume la compatibilidad de los tipos de bloqueo a nivel de tabla.

X IX S ES
X conflicto conflicto conflicto
IX conflicto Compatible conflicto
S conflicto conflicto Compatible
ES conflicto Compatible Compatible

Los bloqueos de fila se pueden subdividir según diferentes escenarios:

  • Next-Key Lock

Next-Key Lockes una combinación de un bloqueo de registro en el registro de índice y un bloqueo de espacio en el espacio anterior al registro de índice.

  • bloqueo de espacioGap Lock

Un bloqueo de espacio es un bloqueo en el espacio entre registros de índice, o en el espacio antes del primer registro de índice o después del último registro de índice. El ejemplo SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;evita que otras transacciones 15inserten el valor column t.c1, independientemente de si dicho valor ya existe en la columna, porque los espacios entre todos los valores existentes en el rango están bloqueados.

  • bloqueo de registroRecord Lock

Un bloqueo de registro es un bloqueo en un registro de índice. Ejemplo SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;Impide que cualquier otra transacción inserte, actualice o elimine filas con un valor t.c1de 10.

  • insertar bloqueo de intenciónInsert Intention Locks

Un bloqueo de intención de inserción es un INSERTbloqueo de espacio establecido por una operación antes de insertar una fila. Este bloqueo expresa la intención de la inserción, es decir, varias transacciones que se insertan en el mismo espacio de índice no necesitan esperarse entre sí si no se insertan en la misma posición dentro del espacio. Supongamos que hay registros de índice con valores 4 y 7. Las transacciones separadas que intentan insertar los valores 5 y 6 bloquean cada una la brecha entre 4 y 7 con un bloqueo de intención INSERT antes de adquirir un bloqueo exclusivo en la fila insertada, pero no se bloquean entre sí porque las filas no están en conflicto.

Diferentes cerraduras tienen diferentes posiciones de bloqueo y el rango de bloqueo se muestra aproximadamente en la siguiente figura.

inserte la descripción de la imagen aquí

Además, la marca de información del registro de interbloqueo correspondiente al bloqueo es la siguiente:

  • Bloqueo de grabación (LOCK_REC_NOT_GAP): lock_mode X bloquea la grabación pero no el espacio
  • Bloqueo de espacio (LOCK_GAP):lock_mode X bloquea el espacio antes de la grabación
  • Siguiente clave (LOCK_ORNIDARY): lock_mode X
  • Insertar bloqueo de intención (LOCK_INSERT_INTENTION): lock_mode X bloquea el espacio antes de rec insertar la intención

1.3 Ejemplo de bloqueo de fila

InnoDBEs un índice agrupado, es decir, B+los nodos hoja del árbol almacenan el índice de clave principal y las filas de datos; los InnoDBnodos hoja del índice secundario almacenan el valor de la clave principal, por lo que al consultar datos a través del índice secundario, debe ir a la consulta según la clave primaria Consulta nuevamente en el índice agrupado.

update user set age = 10 where id = 49;
update user set age = 10 where name = 'Tom';

(1) El primer artículo SQLutiliza la clave principal para realizar consultas, solo necesita id=49agregar un bloqueo de escritura (bloqueo X) a la clave principal;

(2) El segundo artículo SQLutiliza la consulta de índice secundario, primero agrega un bloqueo de escritura y luego agrega un bloqueo de escritura a la clave principal name='Tom'de acuerdo con la consulta de índice de clave primaria obtenida .id=49

Los detalles se muestran en la siguiente figura:

inserte la descripción de la imagen aquí
lo anterior se basa en una sola discusión de datos, para múltiples datos:

update user set age = 10 where id > 49;

Pasos:

(1) MySQLLea el primer registro que cumple la condición de acuerdo con la condición de dónde, y InnoDBel motor devuelve el registro de fila y lo bloquea;

(2) MySQLIniciar una solicitud de actualización para actualizar el registro de fila para actualizar este registro;

(3) Repita los pasos (1) y (2) hasta que se modifiquen todos los registros que cumplan las condiciones.

Específicamente como se muestra en la siguiente figura:

inserte la descripción de la imagen aquí

2. Preparación

2.1 Crear una tabla de datos e inicializarla

create table dead_lock_test
(
    id int auto_increment
        primary key,
    v1 int not null,
    v2 int not null
);

insert into  dead_lock_test (v1,v2) value (1,1);
insert into  dead_lock_test (v1,v2) value (2,2);
insert into  dead_lock_test (v1,v2) value (3,3);

Cabe señalar que solo existe el índice de clave principal en la tabla de datos. Además, el motor de base de datos predeterminado es InnoDBy el nivel de aislamiento de transacciones es RR(lectura repetible, en lugar de RCresolver lecturas fantasmas).

2.2 Monitoreo de cerradura abierta

Utilice la siguiente declaración para habilitar MySQLla supervisión de bloqueo:

# 开启
set GLOBAL innodb_status_output=ON;
set GLOBAL innodb_status_output_locks=ON;

# 关闭
set GLOBAL innodb_status_output_locks=OFF;

3. Reproducción de escenas

Abra dos conexiones de bases de datos y ejecute las siguientes SQLdeclaraciones respectivamente

# session1
start transaction ;
insert into  dead_lock_test (v1,v2) value (4,4);
delete from dead_lock_test where v1 = 4 and v2 = 4;
commit;

# session2
start transaction;
insert into  dead_lock_test (v1,v2) value (5,5);
delete from dead_lock_test where v1 = 5 and v2 = 5;
commit;

No haga preguntas como solo dos SQL en la transacción, simplemente elimine después de la inserción y retroceda (no sé por qué se escribió así).

Los pasos de ejecución de la transacción se muestran en la siguiente tabla:

inserte la descripción de la imagen aquí
La show engine innodb status;información de la transacción del extracto de ejecución es la siguiente:

------------
TRANSACTIONS
------------
Trx id counter 91328
Purge done for trx's n:o < 91327 undo n:o < 0 state: running but idle
History list length 19
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 91327, ACTIVE 37 sec
1 lock struct(s), heap size 1136, 0 row lock(s), undo log entries 1
MySQL thread id 24, OS thread handle 15668, query id 3147 localhost 127.0.0.1 root
TABLE LOCK table `igw_proxy_rule_management`.`dead_lock_test` trx id 91327 lock mode IX
---TRANSACTION 91322, ACTIVE 44 sec
1 lock struct(s), heap size 1136, 0 row lock(s), undo log entries 1
MySQL thread id 23, OS thread handle 22788, query id 3103 localhost 127.0.0.1 root
TABLE LOCK table `igw_proxy_rule_management`.`dead_lock_test` trx id 91322 lock mode IX

La información de la transacción actual se extrae del contenido de salida. Actualmente hay dos transacciones en ejecución, trx ida saber 91322y 91327.

TABLE LOCK tableigw_proxy_rule_management.dead_lock_testtrx id 91322 lock mode IX

dead_lock_test Agregar bloqueo IX en la mesa

91322session1correspondencia comercial 91327_session2

3.2 pasantía2

Después de la ejecución delete from dead_lock_test where v1 = 4 and v2 = 4;, se puede encontrar que la transacción actual está bloqueada.

La show engine innodb status;información de la transacción del extracto de ejecución es la siguiente:

------------
TRANSACTIONS
------------
Trx id counter 91332
Purge done for trx's n:o < 91332 undo n:o < 0 state: running but idle
History list length 21
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 91327, ACTIVE 58 sec
* 2 lock strcut(s): 事务91327中锁链表长度为2(每个链表节点表示该事务持有的一个锁结构,包括表锁/记录锁等),当前事务包含表锁(IX)以及一个行锁(记录锁);
* 1 row lock(s):当前事务持有的行锁个数;
* undo log entries 1:当前事务的undo log个数
2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1
MySQL thread id 24, OS thread handle 15668, query id 3147 localhost 127.0.0.1 root
* TABLE LOCK:当前事务持有的表锁(IX)
TABLE LOCK table `igw_proxy_rule_management`.`dead_lock_test` trx id 91327 lock mode IX
* RECORD LOCKS:当前事务持有的行锁(lock_mode X locks rec but not gap)
* space id 92: dead_lock_test所在空间编号
* page no 4: 当前记录所在页码
RECORD LOCKS space id 92 page no 4 n bits 72 index PRIMARY of table `igw_proxy_rule_management`.`dead_lock_test` trx id 91327 lock_mode X locks rec but not gap
* 行锁信息: heap no=6
Record lock, heap no 6 PHYSICAL RECORD: n_fields 5; compact format; info bits 0

 0: len 4; hex 80000005; asc     ;; * hex 80000005:当前加锁的记录id=5
 1: len 6; hex 0000000164bf; asc     d ;;   * hex 0000000164bf: 事务ID;
 2: len 7; hex 81000000b20110; asc        ;;    * hex 81000000b20110: 回滚指针;
 3: len 4; hex 80000005; asc     ;; * hex 80000005: v1字段对应数值;
 4: len 4; hex 80000005; asc     ;; * hex 80000005:v2字段对应数值;

---TRANSACTION 91322, ACTIVE 65 sec fetching rows
* tables in use 1: 有1个表正在被使用;
* locked 1: 有一个表锁
mysql tables in use 1, locked 1
* LOCK WAIT:事务91322处于锁等待状态;其他字段解释详见上问
LOCK WAIT 5 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 2
MySQL thread id 23, OS thread handle 22788, query id 3199 localhost 127.0.0.1 root updating
* 事务91322当前执行SQL语句
/* ApplicationName=DataGrip 2021.1.1 */ delete from dead_lock_test where v1 = 4 and v2 = 4
* 事务91322等待的锁信息
------- TRX HAS BEEN WAITING 8 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 92 page no 4 n bits 72 index PRIMARY of table `igw_proxy_rule_management`.`dead_lock_test` trx id 91322 lock_mode X waiting
* 事务91322等待的记录锁(锁对应记录主键为5,被事务91327持有)
Record lock, heap no 6 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 0000000164bf; asc     d ;;
 2: len 7; hex 81000000b20110; asc        ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000005; asc     ;;

------------------
* 以下展示事务91322所持有的锁以及尝试获取的锁,首先是表意向锁(IX锁)
TABLE LOCK table `igw_proxy_rule_management`.`dead_lock_test` trx id 91322 lock mode IX
RECORD LOCKS space id 92 page no 4 n bits 72 index PRIMARY of table `igw_proxy_rule_management`.`dead_lock_test` trx id 91322 lock_mode X
* 记录锁(锁对应记录主键为1)
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;;
 1: len 6; hex 0000000164b3; asc     d ;;
 2: len 7; hex 81000000ad0110; asc        ;;
 3: len 4; hex 80000001; asc     ;;
 4: len 4; hex 80000001; asc     ;;

* 记录锁(锁对应记录主键为2)
Record lock, heap no 3 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000002; asc     ;;
 1: len 6; hex 0000000164b4; asc     d ;;
 2: len 7; hex 82000000ad0110; asc        ;;
 3: len 4; hex 80000002; asc     ;;
 4: len 4; hex 80000002; asc     ;;

* 记录锁(锁对应记录主键为3)
Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000003; asc     ;;
 1: len 6; hex 0000000164b9; asc     d ;;
 2: len 7; hex 81000000b00110; asc        ;;
 3: len 4; hex 80000003; asc     ;;
 4: len 4; hex 80000003; asc     ;;

* 记录锁:锁定记录(添加记录时创建的锁)
RECORD LOCKS space id 92 page no 4 n bits 72 index PRIMARY of table `igw_proxy_rule_management`.`dead_lock_test` trx id 91322 lock_mode X locks rec but not gap
Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 32
 0: len 4; hex 80000004; asc     ;;
 1: len 6; hex 0000000164ba; asc     d ;;
 2: len 7; hex 020000011a03cb; asc        ;;
 3: len 4; hex 80000004; asc     ;;
 4: len 4; hex 80000004; asc     ;;

* 间隙锁:锁定记录(删除记录时创建的锁,在RR模式下生效,主要解决幻读)
* 需要注意,InnoDB的删除记录不是物理删除,而是标记删除(等待后续记录覆盖),因此可理解删除类似于更新操作
RECORD LOCKS space id 92 page no 4 n bits 72 index PRIMARY of table `igw_proxy_rule_management`.`dead_lock_test` trx id 91322 lock_mode X locks gap before rec
Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 32
 0: len 4; hex 80000004; asc     ;;
 1: len 6; hex 0000000164ba; asc     d ;;
 2: len 7; hex 020000011a03cb; asc        ;;
 3: len 4; hex 80000004; asc     ;;
 4: len 4; hex 80000004; asc     ;;

* 事务91322尝试获取的锁(被事务91327持有)
RECORD LOCKS space id 92 page no 4 n bits 72 index PRIMARY of table `igw_proxy_rule_management`.`dead_lock_test` trx id 91322 lock_mode X waiting
Record lock, heap no 6 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 0000000164bf; asc     d ;;
 2: len 7; hex 81000000b20110; asc        ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000005; asc     ;;

91322(1) Como se puede ver en los comentarios anteriores, cuando una transacción intenta eliminarse, agregará bloqueos de registros a todos los registros de la tabla.

Esto se debe a que la condición de eliminación de registros actual es que v1 = 4 and v2 = 4no se haya establecido ningún índice correspondiente en los campos v1 y v2.

Debido a que la clave principal no se puede determinar a través del índice, MySQLprimero intentará bloquear dead_lock_testtodos los registros en la tabla actual para agregar bloqueos de registros (puede establecer parámetros para la optimización y liberar gradualmente los bloqueos de registros en los registros que no cumplen con las condiciones). según donde condiciones).

(2) La transacción 91322intenta dead_lock_testagregar bloqueos a todos los registros de la tabla y descubre que los registros han sido bloqueados (id=5)por la transacción , por lo que la transacción solo puede esperar a que la transacción abandone el bloqueo del registro.913279132291327

3.3 etapa 3

Después de ejecutar delete from dead_lock_test where v1 = 5 and v2 = 5;, puede encontrar la salida del terminal:

[2021-05-13 15:33:29] [40001][1213] Deadlock found when trying to get lock; try restarting transaction

Ejecute show engine innodb status;la información de interbloqueo extraída de la siguiente manera:

Debido a que hay muchos contenidos, la explicación ya no aparece en la lista. Para obtener más detalles, consulte la sección de comentarios en chino de la información de salida.

------------------------
LATEST DETECTED DEADLOCK
------------------------
2021-05-13 17:27:09 0xca4
*** (1) TRANSACTION:
* 事务91322持有锁情况,在stage2已经详细解释,此处不再赘述
TRANSACTION 91322, ACTIVE 78 sec fetching rows
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 2
MySQL thread id 23, OS thread handle 22788, query id 3199 localhost 127.0.0.1 root updating
/* ApplicationName=DataGrip 2021.1.1 */ delete from dead_lock_test where v1 = 4 and v2 = 4

*** (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 92 page no 4 n bits 72 index PRIMARY of table `igw_proxy_rule_management`.`dead_lock_test` trx id 91322 lock_mode X
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;;
 1: len 6; hex 0000000164b3; asc     d ;;
 2: len 7; hex 81000000ad0110; asc        ;;
 3: len 4; hex 80000001; asc     ;;
 4: len 4; hex 80000001; asc     ;;

Record lock, heap no 3 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000002; asc     ;;
 1: len 6; hex 0000000164b4; asc     d ;;
 2: len 7; hex 82000000ad0110; asc        ;;
 3: len 4; hex 80000002; asc     ;;
 4: len 4; hex 80000002; asc     ;;

Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000003; asc     ;;
 1: len 6; hex 0000000164b9; asc     d ;;
 2: len 7; hex 81000000b00110; asc        ;;
 3: len 4; hex 80000003; asc     ;;
 4: len 4; hex 80000003; asc     ;;


*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 92 page no 4 n bits 72 index PRIMARY of table `igw_proxy_rule_management`.`dead_lock_test` trx id 91322 lock_mode X waiting
Record lock, heap no 6 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 0000000164bf; asc     d ;;
 2: len 7; hex 81000000b20110; asc        ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000005; asc     ;;


*** (2) TRANSACTION:
TRANSACTION 91327, ACTIVE 71 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 24, OS thread handle 15668, query id 3237 localhost 127.0.0.1 root updating
/* ApplicationName=DataGrip 2021.1.1 */ delete from dead_lock_test where v1 = 5 and v2 = 5

*** (2) HOLDS THE LOCK(S):
* 事务91327持有记录(id=5)的记录锁,此锁正在被事务91322等待持有
RECORD LOCKS space id 92 page no 4 n bits 72 index PRIMARY of table `igw_proxy_rule_management`.`dead_lock_test` trx id 91327 lock_mode X locks rec but not gap
Record lock, heap no 6 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000005; asc     ;;
 1: len 6; hex 0000000164bf; asc     d ;;
 2: len 7; hex 81000000b20110; asc        ;;
 3: len 4; hex 80000005; asc     ;;
 4: len 4; hex 80000005; asc     ;;


*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
* 事务91327等待持有记录锁,锁信息见后续解释
RECORD LOCKS space id 92 page no 4 n bits 72 index PRIMARY of table `igw_proxy_rule_management`.`dead_lock_test` trx id 91327 lock_mode X waiting
* 事务91327等待持有记录(id=1)的记录锁(delete无法走索引查询,因此会尝试对所有表记录进行加锁,但是事务91322持有id=1/2/3/4的记录锁,死锁条件构成)
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000001; asc     ;;
 1: len 6; hex 0000000164b3; asc     d ;;
 2: len 7; hex 81000000ad0110; asc        ;;
 3: len 4; hex 80000001; asc     ;;
 4: len 4; hex 80000001; asc     ;;

*** WE ROLL BACK TRANSACTION (2)

Se puede ver en lo anterior:

(1) Cuando una transacción 91322ejecuta una operación de eliminación, intente adquirir los bloqueos de registros de todos los registros en la tabla, donde la transacción mantiene los (id=5)bloqueos de registros;91327

(2) 91327Cuando la transacción ejecuta la operación de eliminación, intenta obtener los bloqueos de registros de todos los registros de la tabla y descubre que los (id=1/2/3/4)bloqueos de registros los 91322mantiene la transacción;

(3) En este punto, la transacción 91322y la transacción 91327se esperan mutuamente y se forma un punto muerto.

4. Soluciones

4.1 Agregar índice

Del análisis anterior se puede ver que al eliminar, debido a que la condición donde no puede usar el índice, intentará MySQLagregar bloqueos de registros a todos los registros de la tabla, lo que provocará un punto muerto.

Solo necesitamos crear un índice conjunto en los campos v1 y v2 para limitar el alcance de los conflictos de registros.

create index dead_lock_test_v2_v1_index on dead_lock_test (v1, v2);

Aquí no se establece un índice único. Si se consultan varias transacciones en función del índice, los registros bloqueados se superpondrán y es fácil reproducir el fenómeno del punto muerto.

Sin embargo, la inserción de datos en el lado comercial actual puede garantizar que no habrá registros superpuestos en un corto período de tiempo y habrá algunos datos duplicados en la tabla, por lo que no se utilizará un índice único.

4.2 Finales

Agregue un índice a la tabla. Se agrega y luego se elimina en la transacción, lo que se realiza mediante reversión.


Referencia:
https://www.lmonkey.com/t/vEwdR9pyJ
https://dev.mysql.com/doc/refman/5.6/en/innodb-locking.html

Supongo que te gusta

Origin blog.csdn.net/qq_25854057/article/details/127092124
Recomendado
Clasificación