MySQL
SELECT ... FOR UPDATE con ACTUALIZACIÓN
El uso de transacciones de InnoDB (confirmación automática desactivada), un SELECT ... FOR UPDATE
permite una sesión para bloquear temporalmente un registro en particular (o registros) de manera que ninguna otra sesión puede actualizar eso.Luego, dentro de la misma transacción, la sesión puede realizar un UPDATE
en el mismo registro y confirmar o revertir la transacción. Esto le permitiría bloquear el registro para que ninguna otra sesión pueda actualizarlo mientras quizás haga otra lógica comercial.
Esto se logra con el bloqueo. InnoDB utiliza índices para bloquear registros, por lo que bloquear un registro existente parece fácil: simplemente bloquea el índice para ese registro.
SELECT ... FOR UPDATE con INSERT
Sin embargo, para utilizar con SELECT ... FOR UPDATE
INSERT
, ¿cómo bloquear un índice para un disco que aún no existe? Si está utilizando el nivel de aislamiento predeterminado de REPEATABLE READ
, InnoDB también utilizará bloqueos. Siempre que conozca el id
(o incluso el rango de identificadores) para bloquear, InnoDB puede bloquear el espacio para que no se pueda insertar ningún otro registro en ese espacio hasta que hayamos terminado.
Si su columna id
eran una columna de incremento automático, entonces SELECT ... FOR UPDATE
con INSERT INTO
sería problemático porque no vas a saber lo que el nuevo id
fue hasta insertarla. Sin embargo, como conoce el id
que desea insertar, SELECT ... FOR UPDATE
con INSERT
funcionará.
Claves clínicas
En el nivel de aislamiento por omisión, SELECT ... FOR UPDATE
en un registro inexistente hace no bloque de otras transacciones. Entonces, si dos transacciones hacen un SELECT ... FOR UPDATE
en el mismo registro de índice inexistente, ambos obtendrán el bloqueo y ninguna de las transacciones podrá actualizar el registro. De hecho, si ambos lo intentan, se detectará un interbloqueo y uno se revertirá.
Por lo tanto, si usted no quiere hacer frente a un callejón sin salida, que sólo podría hacer lo siguiente:
INSERT INTO ...
iniciar una transacción, y realizar la INSERT
. Haz tu lógica de negocios y confirma o revierte la transacción. Tan pronto como realice el INSERT
en el índice de registro inexistente en la primera transacitón, todas las demás transacciones se bloquearán si intentan INSERT
un registro con el mismo índice único. Si la segunda transacción intenta insertar un registro con el mismo índice después de que la primera transacción confirme la inserción, recibirá un error de "clave duplicada". Manejar en consecuencia.
SELECT ... LOCK IN SHARE MODE
Si selecciona con LOCK IN SHARE MODE
antes de la INSERT
, si una transacción anterior ha insertado ese registro, pero no se ha comprometido todavía, la SELECT ... LOCK IN SHARE MODE
bloqueará hasta que la transacción previa ha completado.
lo tanto, para reducir la posibilidad de errores de claves duplicadas, especialmente si mantiene los bloqueos por un tiempo mientras se realiza la lógica de negocio antes de comprometerse ellos o rodar de nuevo:
SELECT bar FROM FooBar WHERE foo = ? LOCK FOR UPDATE
- Si devuelve ningún registro, a continuación,
INSERT INTO FooBar (foo, bar) VALUES (?, ?)
¿el MSSQL incluso apoyar esta sintaxis? –
Tiene "con updlock", que creo que es más o menos lo mismo. –