2010-03-29 20 views
7

Tengo un problema extraño (al menos para mí :)) con la facilidad de bloqueo de MySQL.Mysql SELECCIONAR PARA ACTUALIZAR - extraño problema

Tengo una tabla:

create table `test` ( 
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=latin1 

Con estos datos:

+ ---- +
| id |
+ ---- +
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 10 |
| 11 |
| 12 |
+ ---- +

Ahora tengo 2 clientes con estos comandos ejecutados por el principio:

conjunto de confirmación automática = 0;
establece el nivel de aislamiento de la transacción de sesión serializable;
begin;

Ahora la parte más interesante. El primer cliente ejecuta esta consulta: (hace un intento de insertar una fila con id igual a 9)

SELECCIONE * de la prueba donde id = 9 PARA ACTUALIZAR;
Empty set (0.00 sec)

A continuación, el segundo cliente hace lo mismo:

SELECT * de prueba en la que id = 9 FOR UPDATE;
Empty set (0.00 sec)

Mi pregunta es: ¿Por qué el segundo cliente no bloquea? La primera consulta debe haber configurado un bloqueo de espacio exclusivo porque FOR UPDATE se ha utilizado y el segundo cliente debería bloquearse.

Si me equivoco, ¿podría alguien decirme cómo hacerlo correctamente?

La versión de MySQL que uso es: 5.1.37-1ubuntu5.1

+0

No bloquea porque ha bloqueado correctamente ** filas **. – Pacerier

Respuesta

3

Porque en ese momento, es seguro para devolver el resultado (vacío) - no hay bloqueo para fijar para el registro con id = 9 ya que eso no existe y, por lo tanto, no se puede actualizar: no creo que pueda confiar en la configuración de bloqueos de lectura en ese caso. Sin embargo, debería establecer un bloqueo de escritura en id = 9.

Si en un momento posterior, una de las transacciones actualiza la tabla y toca los mismos datos que otra transacción, la actualización probablemente bloqueará en una de las transacciones y luego fallará si la otra transacción cometió esos datos.Es perfectamente normal que las transacciones fallen en escenarios como este, dejándote manejarlo, que generalmente es una cuestión de reintentar la transacción.

Si hubiera un registro con id = 9 probablemente vería el bloque 2. select hasta que la primera transacción haya finalizado, ya que ahora hay un registro que debe leerse bloqueado en caso de que la primera transacción decida actualizar esa fila

+1

Sí, si hay un registro con id = 9, los 2dos bloques de selección. Entonces, ¿cómo debería "reservar" el id 9? Tengo este problema porque estoy almacenando alguna relación entre pares de objetos y solo quiero una fila para un par dado de objetos. –

+0

Difícil de decir exactamente lo que estás tratando de hacer. ¿Alguna de tus transacciones creará id = 9? en cuyo caso la otra transacción fallará/se retrotraerá. – nos

+0

Estoy tratando de implementar algo como esto en Java: if (! RowExists (9)) { createRowWithId (9); } else { return "Error"; } Y obtengo identificaciones duplicadas ... –