tipos - Al usar el bloqueo FOR UPDATE de MySQL, ¿qué está exactamente bloqueado?
tipos de bloqueos mysql (4)
¿Por qué no lo probamos?
Configurar la base de datos
CREATE DATABASE so1;
USE so1;
CREATE TABLE notification (`id` BIGINT(20), `date` DATE, `text` TEXT) ENGINE=InnoDB;
INSERT INTO notification(id, `date`, `text`) values (1, ''2011-05-01'', ''Notification 1'');
INSERT INTO notification(id, `date`, `text`) values (2, ''2011-05-02'', ''Notification 2'');
INSERT INTO notification(id, `date`, `text`) values (3, ''2011-05-03'', ''Notification 3'');
INSERT INTO notification(id, `date`, `text`) values (4, ''2011-05-04'', ''Notification 4'');
INSERT INTO notification(id, `date`, `text`) values (5, ''2011-05-05'', ''Notification 5'');
Ahora, inicie dos conexiones a la base de datos
Conexión 1
BEGIN;
SELECT * FROM notification WHERE `date` >= ''2011-05-03'' FOR UPDATE;
Conexión 2
BEGIN;
Si MySQL bloquea todas las filas, la siguiente instrucción se bloquearía. Si solo bloquea las filas que devuelve, no debería bloquear.
SELECT * FROM notification WHERE `date` = ''2011-05-02'' FOR UPDATE;
Y de hecho sí bloquea.
Curiosamente, tampoco podemos agregar registros que se leerían, es decir,
INSERT INTO notification(id, `date`, `text`) values (6, ''2011-05-06'', ''Notification 6'');
bloques también!
No puedo estar seguro en este punto si MySQL simplemente sigue adelante y bloquea toda la tabla cuando un cierto porcentaje de filas está bloqueado, o donde en realidad es realmente inteligente para asegurarse de que el resultado de la consulta SELECT ... FOR UPDATE
nunca pueda ser cambiado por otra transacción (con INSERT
, UPDATE
o DELETE
) mientras se mantiene el bloqueo.
Este no es un pseudo-código de consulta MySQL completo / correcto:
Select *
from Notifications as n
where n.date > (CurrentDate-10 days)
limit by 1
FOR UPDATE
http://dev.mysql.com/doc/refman/5.0/en/select.html declara: Si usa FOR UPDATE con un motor de almacenamiento que usa bloqueos de página o fila, las filas examinadas por la consulta se bloquean mediante escritura hasta que el fin de la transacción actual
¿Está aquí solo el único registro devuelto bloqueado por MySQL o todos los registros que tiene que escanear para encontrar el único registro?
Bloquea todas las filas seleccionadas por consulta.
Los siguientes enlaces de la página de documentación que publicó brindan más información sobre el locking . En esta página
A SELECT ... FOR UPDATE lee los últimos datos disponibles, configurando bloqueos exclusivos en cada fila que lee. Por lo tanto, establece los mismos bloqueos que una ACTUALIZACIÓN SQL buscada establecería en las filas.
Parece bastante claro que son todas las filas las que tiene que escanear.
Sé que esta pregunta es bastante antigua, pero he querido compartir los resultados de algunas pruebas relevantes que he hecho con columnas indexadas, que han arrojado algunos resultados bastante extraños.
Estructura de la tabla:
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`notid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
12 filas insertadas con INSERT INTO t1 (notid) VALUES (1), (2),..., (12)
. En la conexión 1 :
BEGIN;
SELECT * FROM t1 WHERE id=5 FOR UPDATE;
En la conexión 2 , las siguientes declaraciones están bloqueadas:
SELECT * FROM t1 WHERE id!=5 FOR UPDATE;
SELECT * FROM t1 WHERE id<5 FOR UPDATE;
SELECT * FROM t1 WHERE notid!=5 FOR UPDATE;
SELECT * FROM t1 WHERE notid<5 FOR UPDATE;
SELECT * FROM t1 WHERE id<=4 FOR UPDATE;
La parte más extraña es que SELECT * FROM t1 WHERE id>5 FOR UPDATE;
no está bloqueado , ni ninguno de
...
SELECT * FROM t1 WHERE id=3 FOR UPDATE;
SELECT * FROM t1 WHERE id=4 FOR UPDATE;
SELECT * FROM t1 WHERE id=6 FOR UPDATE;
SELECT * FROM t1 WHERE id=7 FOR UPDATE;
...
También me gustaría señalar que parece que toda la tabla está bloqueada cuando la condición WHERE
en la consulta de la conexión 1 coincide con una fila no indexada. Por ejemplo, cuando la conexión 1 ejecuta SELECT * FROM t1 WHERE notid=5 FOR UPDATE
, todas las consultas de selección con FOR UPDATE
y UPDATE
consultas desde la conexión 2 están bloqueadas.
- EDITAR -
Esta es una situación bastante específica, pero fue la única que pude encontrar que exhibe este comportamiento:
Conexión 1:
BEGIN;
SELECT *, @x:=@x+id AS counter FROM t1 CROSS JOIN (SELECT @x:=0) b HAVING counter>5 LIMIT 1 FOR UPDATE;
+----+-------+-------+---------+
| id | notid | @x:=0 | counter |
+----+-------+-------+---------+
| 3 | 3 | 0 | 9 |
+----+-------+-------+---------+
1 row in set (0.00 sec)
De la conexión 2 :
SELECT * FROM t1 WHERE id=2 FOR UPDATE;
está bloqueado;
SELECT * FROM t1 WHERE id=4 FOR UPDATE;
no está bloqueado