sql >> Base de Datos >  >> RDS >> Oracle

¿SELECCIONAR PARA ACTUALIZAR evita que se inserten otras conexiones cuando la fila no está presente?

MySQL

SELECCIONE... PARA ACTUALIZAR con ACTUALIZAR

Usando transacciones con InnoDB (compromiso automático desactivado), un SELECT ... FOR UPDATE permite que una sesión bloquee temporalmente un registro (o registros) en particular para que ninguna otra sesión pueda actualizarlo. Luego, dentro de la misma transacción, la sesión puede realizar una 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 tal vez haga alguna otra lógica empresarial.

Esto se logra con el bloqueo. InnoDB utiliza índices para bloquear registros, por lo que bloquear un registro existente parece fácil:simplemente bloquee el índice para ese registro.

SELECCIONE... PARA ACTUALIZAR con INSERTAR

Sin embargo, para usar SELECT ... FOR UPDATE con INSERT , ¿cómo bloquea un índice para un registro que aún no existe? Si está utilizando el nivel de aislamiento predeterminado de REPEATABLE READ , InnoDB también utilizará brecha Cerraduras. Siempre que conozca el id (o incluso un rango de ID) para bloquear, luego InnoDB puede bloquear el espacio para que no se pueda insertar ningún otro registro en ese espacio hasta que terminemos con él.

Si su id columna fuera una columna de incremento automático, entonces SELECT ... FOR UPDATE con INSERT INTO sería problemático porque no sabría cuál es el nuevo id fue hasta que lo insertaste. Sin embargo, dado que conoce el id que desea insertar, SELECT ... FOR UPDATE con INSERT funcionará.

ADVERTENCIA

En el nivel de aislamiento predeterminado, SELECT ... FOR UPDATE en un registro inexistente no bloquear otras transacciones. Entonces, si dos transacciones ambas hacen un SELECT ... FOR UPDATE en el mismo registro de índice inexistente, ambos obtendrán el bloqueo y ninguna transacción podrá actualizar el registro. De hecho, si lo intentan, se detectará un interbloqueo.

Por lo tanto, si no quiere lidiar con un interbloqueo, puede hacer lo siguiente:

INSERTAR EN...

Inicie una transacción y realice INSERT . Haga su lógica comercial y confirme o revierta la transacción. Tan pronto como hagas INSERT en el índice de registro inexistente en la primera transacció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, obtendrá un error de "clave duplicada". Manejar en consecuencia.

SELECCIONA... BLOQUEAR EN MODO COMPARTIR

Si selecciona con LOCK IN SHARE MODE antes del INSERT , si una transacción anterior ha insertado ese registro pero aún no se ha confirmado, SELECT ... LOCK IN SHARE MODE se bloqueará hasta que se complete la transacción anterior.

Entonces, para reducir la posibilidad de errores de clave duplicada, especialmente si mantiene los bloqueos por un tiempo mientras realiza la lógica comercial antes de confirmarlos o revertirlos:

  1. SELECT bar FROM FooBar WHERE foo = ? LOCK FOR UPDATE
  2. Si no se devolvieron registros, entonces
  3. INSERT INTO FooBar (foo, bar) VALUES (?, ?)