¿Cómo se implementa correctamente el bloqueo optimista en MySQL?
Nuestro equipo ha deducido que debemos hacer el # 4 a continuación o de lo contrario existe el riesgo de que otro hilo pueda actualizar la misma versión del registro, pero nos gustaría validar que esta es la mejor manera de hacerlo.
- Cree un campo de versión en la tabla para la que desea usar el bloqueo optimista, por ejemplo, columna nombre = "versión"
- En selecciones, asegúrese de incluir la columna de versión y tome nota de la versión
- En una actualización posterior del registro, la declaración de actualización debe emitir "where version = X" donde X es la versión que recibimos en el n. ° 2 y establecer el campo de versión durante esa declaración de actualización en X + 1
- Realice un
SELECT FOR UPDATE
registro en el registro que vamos a actualizar para que serialicemos quién puede realizar cambios en el registro que estamos tratando de actualizar.
Para aclarar, estamos tratando de evitar que dos subprocesos que seleccionan el mismo registro en la misma ventana de tiempo donde toman la misma versión del registro se sobrescriban entre sí si intentan actualizar el registro al mismo tiempo. Creemos que a menos que hagamos el n. ° 4, existe la posibilidad de que si ambos hilos ingresan sus transacciones respectivas al mismo tiempo (pero aún no han emitido sus actualizaciones), cuando van a actualizar, el segundo hilo que usará la ACTUALIZACIÓN ... donde version = X funcionará con datos antiguos.
¿Estamos en lo cierto al pensar que debemos hacer este bloqueo pesimista al actualizar a pesar de que estamos usando campos de versión / bloqueo optimista?
SELECT ... FOR UPDATE
o bloqueo optimista por versiones de fila, pero no ambos. Ver detalles en la respuesta.Respuestas:
Tu desarrollador está equivocado. Necesita versiones de fila o de uno , no ambas.
SELECT ... FOR UPDATE
Pruébalo y verás. Tres sesiones abiertas de MySQL
(A)
,(B)
y(C)
con la misma base de datos.En
(C)
cuestión:En ambos
(A)
y(B)
emite unUPDATE
que prueba y establece la versión de la fila, cambiando elwinner
texto en cada uno para que pueda ver qué sesión es cuál:Ahora adentro
(C)
,UNLOCK TABLES;
para liberar el bloqueo.(A)
y(B)
correrá por el bloqueo de la fila. Uno de ellos ganará y obtendrá el bloqueo. El otro bloqueará la cerradura. El ganador que obtuvo el bloqueo procederá a cambiar la fila. Suponiendo que(A)
es el ganador, ahora puede ver la fila modificada (aún sin confirmar, por lo que no es visible para otras transacciones) con unSELECT * FROM test WHERE id = 1
.Ahora
COMMIT
en la sesión ganadora, digamos(A)
.(B)
obtendrá el bloqueo y procederá con la actualización. Sin embargo, la versión ya no coincide, por lo que no cambiará filas, según lo informado por el resultado del recuento de filas. Solo unoUPDATE
tuvo algún efecto, y la aplicación cliente puede ver claramente cuálUPDATE
tuvo éxito y cuál falló. No es necesario más bloqueo.Vea los registros de sesión en pastebin aquí . Utilicé
mysql --prompt="A> "
etc. para facilitar la diferencia entre sesiones. Copié y pegué la salida intercalada en secuencia de tiempo, por lo que no es una salida totalmente sin procesar y es posible que haya cometido errores al copiarla y pegarla. Pruébelo usted mismo para ver.Si hubieras no añadido un campo de versión de fila, a continuación, que tendría que
SELECT ... FOR UPDATE
ser capaz de garantizar de manera fiable el pedido.Si lo piensa, a
SELECT ... FOR UPDATE
es completamente redundante si está haciendo inmediatamenteUPDATE
sin volver a usar los datos delSELECT
, o si está usando el control de versiones de fila. ElUPDATE
tomará un candado de todos modos. Si alguien más actualiza la fila entre su lectura y la escritura posterior, su versión ya no coincidirá, por lo que su actualización fallará. Así es como funciona el bloqueo optimista.El propósito de
SELECT ... FOR UPDATE
es:SERIALIZABLE
aislamiento o control de versiones de fila.No necesita utilizar tanto el bloqueo optimista (versiones de fila) como
SELECT ... FOR UPDATE
. Usar uno u otro.fuente
No se necesitan bloqueos (ni tabla, ni transacción), ni siquiera deseados:
fuente