Bloqueo optimista versus pesimista
Entiendo las diferencias entre el bloqueo optimista y pesimista. Ahora bien, ¿alguien podría explicarme cuándo usaría cualquiera de los dos en general?
¿Y la respuesta a esta pregunta cambia dependiendo de si estoy usando o no un procedimiento almacenado para realizar la consulta?
Pero solo para comprobarlo, optimista significa "no bloquear la mesa mientras lee" y pesimista significa "bloquear la mesa mientras lee".
El bloqueo optimista es una estrategia en la que lees un registro, tomas nota de un número de versión (otros métodos para hacer esto implican fechas, marcas de tiempo o sumas de verificación/hashes) y verificas que la versión no haya cambiado antes de volver a escribir el registro. Cuando vuelve a escribir el registro, filtra la actualización en la versión para asegurarse de que sea atómica. (es decir, no se ha actualizado entre el momento en que verifica la versión y escribe el registro en el disco) y actualiza la versión de una sola vez.
Si el registro está sucio (es decir, una versión diferente a la suya), cancele la transacción y el usuario puede reiniciarla.
Esta estrategia es más aplicable a sistemas de gran volumen y arquitecturas de tres niveles donde no necesariamente se mantiene una conexión a la base de datos para su sesión. En esta situación, el cliente no puede mantener los bloqueos de la base de datos ya que las conexiones se toman de un grupo y es posible que no esté utilizando la misma conexión de un acceso al siguiente.
El bloqueo pesimista es cuando bloquea el registro para su uso exclusivo hasta que haya terminado con él. Tiene una integridad mucho mejor que el bloqueo optimista, pero requiere que usted tenga cuidado con el diseño de su aplicación para evitar interbloqueos . Para utilizar el bloqueo pesimista, necesita una conexión directa a la base de datos (como suele ser el caso en una aplicación cliente-servidor de dos niveles ) o un ID de transacción disponible externamente que se puede utilizar independientemente de la conexión.
En el último caso, abres la transacción con el TxID y luego te vuelves a conectar usando ese ID. El DBMS mantiene los bloqueos y le permite recuperar la sesión a través del TxID. Así es como funcionan las transacciones distribuidas que utilizan protocolos de confirmación de dos fases (como XA o COM+ Transactions ).
Cuando se trata de conflictos, tienes dos opciones:
- Puedes intentar evitar el conflicto, y eso es lo que hace el bloqueo pesimista.
- O bien, podría permitir que se produzca el conflicto, pero necesita detectarlo al realizar sus transacciones, y eso es lo que hace el bloqueo optimista.
Ahora, consideremos la siguiente anomalía de Actualización perdida:
La anomalía de Actualización perdida puede ocurrir en el nivel de aislamiento de lectura confirmada.
En el diagrama de arriba podemos ver que Alice cree que puede retirarle 40 account
pero no se da cuenta de que Bob acaba de cambiar el saldo de la cuenta y ahora solo quedan 20 en esta cuenta.
Bloqueo pesimista
El bloqueo pesimista logra este objetivo al adoptar un bloqueo compartido o de lectura en la cuenta para evitar que Bob cambie la cuenta.
En el diagrama anterior, tanto Alice como Bob adquirirán un bloqueo de lectura en la account
fila de la tabla que ambos usuarios han leído. La base de datos adquiere estos bloqueos en SQL Server cuando utiliza lectura repetible o serializable.
Debido a que tanto Alice como Bob han leído el account
valor PK de 1
, ninguno de ellos puede cambiarlo hasta que un usuario libere el bloqueo de lectura. Esto se debe a que una operación de escritura requiere la adquisición de un bloqueo de escritura/exclusivo, y los bloqueos compartidos/de lectura evitan los bloqueos de escritura/exclusivos.
Solo después de que Alice haya confirmado su transacción y se haya liberado el bloqueo de lectura en la account
fila, Bob UPDATE
reanudará y aplicará el cambio. Hasta que Alice libere el bloqueo de lectura, la ACTUALIZACIÓN de Bob se bloquea.
Bloqueo optimista
El bloqueo optimista permite que se produzca el conflicto, pero lo detecta al aplicar la ACTUALIZACIÓN de Alice ya que la versión ha cambiado.
Esta vez tenemos una version
columna adicional. La version
columna se incrementa cada vez que se ejecuta ACTUALIZAR o ELIMINAR, y también se usa en la cláusula WHERE de las declaraciones ACTUALIZAR y ELIMINAR. Para que esto funcione, necesitamos emitir SELECT y leer el actual version
antes de ejecutar UPDATE o DELETE, de lo contrario, no sabríamos qué valor de versión pasar a la cláusula WHERE o incrementar.
Transacciones a nivel de aplicación
Los sistemas de bases de datos relacionales surgieron a finales de los 70 y principios de los 80, cuando un cliente, normalmente, se conectaba a una computadora central a través de una terminal. Es por eso que todavía vemos que los sistemas de bases de datos definen términos como configuración de SESIÓN.
Hoy en día, en Internet, ya no ejecutamos lecturas y escrituras en el contexto de la misma transacción de base de datos y ACID ya no es suficiente.
Por ejemplo, considere el siguiente caso de uso:
Sin un bloqueo optimista, no hay forma de que esta actualización perdida se hubiera detectado incluso si las transacciones de la base de datos utilizaran Serializable. Esto se debe a que las lecturas y escrituras se ejecutan en solicitudes HTTP separadas y, por lo tanto, en diferentes transacciones de bases de datos.
Por lo tanto, el bloqueo optimista puede ayudarle a evitar la pérdida de actualizaciones incluso cuando utiliza transacciones a nivel de aplicación que también incorporan el tiempo de reflexión del usuario.
Conclusión
El bloqueo optimista es una técnica muy útil y funciona bien incluso cuando se utilizan niveles de aislamiento menos estrictos, como lectura confirmada, o cuando se ejecutan lecturas y escrituras en transacciones posteriores de la base de datos.
La desventaja del bloqueo optimista es que el marco de acceso a datos activará una reversión al detectar un OptimisticLockException
, por lo que perderemos todo el trabajo que hemos realizado anteriormente con la transacción que se está ejecutando actualmente.
Cuanta más contención, más conflictos y mayores serán las posibilidades de abortar las transacciones. Las reversiones pueden ser costosas para el sistema de base de datos, ya que necesita revertir todos los cambios pendientes actuales que podrían involucrar tanto a las filas de la tabla como a los registros del índice.
Por esta razón, el bloqueo pesimista podría ser más adecuado cuando los conflictos ocurren con frecuencia, ya que reduce la posibilidad de revertir transacciones.
El bloqueo optimista se utiliza cuando no se esperan muchas colisiones. Cuesta menos realizar una operación normal, pero si la colisión SÍ ocurre, pagaría un precio más alto para resolverla ya que se cancela la transacción.
El bloqueo pesimista se utiliza cuando se anticipa una colisión. Las transacciones que violarían la sincronización simplemente se bloquean.
Para seleccionar el mecanismo de bloqueo adecuado, debe estimar la cantidad de lecturas y escrituras y planificar en consecuencia.
Optimista supone que nada va a cambiar mientras lo lees.
El pesimista supone que algo sucederá y por eso lo bloquea.
Si no es imprescindible que los datos se lean perfectamente utilice optimista. Es posible que obtenga alguna lectura "sucia", pero es mucho menos probable que resulte en puntos muertos y cosas similares.
La mayoría de las aplicaciones web funcionan bien con lecturas sucias; en raras ocasiones, los datos no coinciden exactamente con la siguiente recarga.
Para operaciones de datos exactas (como en muchas transacciones financieras), utilice pesimista. Es esencial que los datos se lean con precisión, sin cambios no mostrados; la sobrecarga adicional de bloqueo vale la pena.
Ah, y el servidor Microsoft SQL tiene como valor predeterminado el bloqueo de página, básicamente la fila que estás leyendo y algunas a cada lado. El bloqueo de filas es más preciso pero mucho más lento. A menudo vale la pena configurar sus transacciones en lectura confirmada o sin bloqueo para evitar interbloqueos durante la lectura.