bloqueo exclusivo de MySQL

stavros.zavrakas:

Tenemos las siguientes tablas:

mysql> desc journeys ;
+---------------+------------+------+-----+---------+-------+
| Field         | Type       | Null | Key | Default | Extra |
+---------------+------------+------+-----+---------+-------+
| journey_id    | char(36)   | NO   | PRI | NULL    |       |
| is_completed  | tinyint(1) | NO   |     | 0       |       |
| user_id       | char(36)   | NO   |     | NULL    |       |
| created_at    | datetime   | NO   |     | NULL    |       |
| updated_at    | datetime   | NO   |     | NULL    |       |
| pack_id       | char(36)   | YES  | MUL | NULL    |       |
| family_id     | char(36)   | YES  | MUL | NULL    |       |
+---------------+------------+------+-----+---------+-------+

mysql> desc packs ;
+---------------+------------+------+-----+---------+-------+
| Field         | Type       | Null | Key | Default | Extra |
+---------------+------------+------+-----+---------+-------+
| pack_id       | char(36)   | NO   | PRI | NULL    |       |
| is_published  | tinyint(1) | NO   |     | 0       |       |
| order         | int(11)    | NO   |     | NULL    |       |
| created_at    | datetime   | NO   |     | NULL    |       |
| updated_at    | datetime   | NO   |     | NULL    |       |
| family_id     | char(36)   | NO   | MUL | NULL    |       |
+---------------+------------+------+-----+---------+-------+

El nivel de aislamiento es REPEATABLE_READ.

De acuerdo con el glosario aquí: https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_exclusive_lock

Un bloqueo exclusivo es una especie de bloqueo que impide que cualquier otra transacción de bloqueo de la misma fila . Dependiendo del nivel de aislamiento, este tipo de bloqueo puede bloquear otras transacciones de la escritura a la misma fila, o también puede bloquear otras transacciones de la lectura de la misma fila.

La lógica que tenemos se parece a la de abajo (la user_idtoma valores diferentes):

START TRANSACTION;
SELECT * FROM journeys WHERE user_id = <user_id> FOR UPDATE ;
# COMMIT;

A continuación hay un poco de prueba. Abro una ventana de terminal (terminal 1) y ejecutar las instrucciones siguientes:

START TRANSACTION;
SELECT * FROM journeys WHERE user_id = user_id_1 FOR UPDATE ;

Entonces abro una segunda ventana de terminal (terminal # 2) y ejecutar las instrucciones siguientes:

START TRANSACTION;
SELECT * FROM journeys WHERE user_id = user_id_2 FOR UPDATE ;

El terminal # 2 ahora se detiene debido a que nunca se confirma la transacción en el terminal # 1.

Mi hipótesis es que debido a la condición en el primer terminal # 1 es diferente de la declaración en la terminal # 2 que el segundo terminal no esperar a que el primero de ellos a cometer. Estoy basando mi suposición sobre la definición de un bloqueo exclusivo que dice que el bloqueo exclusivo impide que cualquier otra transacción de bloqueo de la misma fila. ¿Es esta una suposición errónea? Si es así, ¿cómo pueden lograr para bloquear las filas que tenemos en la primera condición?

Parece que es diferente cuando se utiliza la clave principal de la condición. En el caso por debajo de la terminal # 2 no está esperando el terminal # 1 a cometer.

terminal #1
START TRANSACTION;
SELECT * FROM journeys WHERE journey_id = journey_id_1 FOR UPDATE ;

Las declaraciones en la terminal # 2

terminal #2
START TRANSACTION;
SELECT * FROM journeys WHERE journey_id = journey_id_2 FOR UPDATE ;

Lo que ocurre exactamente con los bloqueos exclusivos cuando tenemos condiciones que no incluyen las claves primarias? Estamos encerrando toda la tabla?

Bill Karwin:

Sí, estás bloqueo de todas las filas de la tabla cuando se tiene una condición en una columna no indexada como user_id.

Los bloqueos se aplican a todas las filas "examinado". Su condición WHERE user_id = <user_id>debe examinar todas las filas de la tabla, y probarlos uno por uno para ver si coinciden con el valor de <user_id>.

Ambas consultas están examinando el conjunto de filas, a pesar de que están en busca de diferentes valores específicos de <user_id>, por lo que entran en conflicto.

Si usted tenía un índice sobre la user_idcolumna, a continuación, MySQL usaría ese índice para encontrar las filas coincidentes en primer lugar, a continuación, sólo las filas coincidentes se convertirían en registros examinados, y por lo tanto estaría cerrada.

Esto no tiene nada que ver con el nivel de aislamiento. Estos tipos de bloqueos ocurren en todos los niveles de aislamiento de transacción.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=372736&siteId=1
Recomendado
Clasificación