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

Implementación de bloqueo optimista en Oracle

Hay dos enfoques generales para el bloqueo.

Primero, tienes un bloqueo pesimista. En este enfoque, bloquea la fila (SELECT ... FOR UPDATE ) que evita que cualquier otra persona cambie la fila. Luego haces el UPDATE . Cuando confirma su cambio, se libera el bloqueo. En este caso, no es necesario tener una columna de número de versión/marca de tiempo (al menos no para permitir el bloqueo) y el código es relativamente fácil.

La desventaja del bloqueo pesimista es que debe mantener el bloqueo todo el tiempo que un usuario esté sentado en una página que pueda editar datos. Esto es técnicamente muy difícil si está creando una aplicación basada en web, ya que HTTP es un protocolo sin estado. La solicitud que muestra inicialmente la página normalmente obtendría una conexión del conjunto de conexiones, haga SELECT , y luego devuelva la conexión al grupo una vez que se haya completado la página. La solicitud posterior para actualizar los datos generalmente ocurriría en una conexión diferente con una sesión de base de datos diferente, por lo que no puede bloquear la fila en la primera sesión y actualizarla en la segunda. Si quisiera bloquear la fila de manera pesimista, necesitaría trabajar mucho en el back-end para asegurarse de que la única conexión de la base de datos estuviera vinculada a una sesión de nivel medio en particular hasta que el usuario terminara de editar los datos. Por lo general, esto tiene un impacto muy negativo en la escalabilidad e introduce todo tipo de problemas de administración de sesiones. ¿Cómo sabe, por ejemplo, si solicité una página, bloqueé una fila y luego cerré mi navegador sin cerrar sesión o hacer un cambio? ¿Cuánto tiempo vas a dejar el registro bloqueado en la base de datos? ¿Qué sucede si alguna otra sesión intenta bloquear la fila? ¿Cuánto tiempo vas a dejar ese bloque de sesión esperando un candado si la primera persona salió a almorzar? En general, las personas no implementan el bloqueo pesimista en las aplicaciones basadas en la web porque administrar las sesiones y el estado de la sesión es demasiado poco práctico.

La segunda opción es el bloqueo optimista. En este enfoque, agrega un número de versión/marca de tiempo a la fila. Usted selecciona este número de versión/marca de tiempo cuando consulta los datos. Luego usas esto en tu WHERE cláusula cuando más tarde realice la actualización y verifique cuántas filas se modificaron realmente. Si modifica exactamente una fila, sabrá que la fila no ha cambiado desde que la leyó. Si modifica 0 filas, sabe que la fila cambió y puede manejar el error.

Entonces, por ejemplo, seleccionaría los datos junto con el número de versión

SELECT address_line1, city, state, zip, version
  FROM addressTable
 WHERE address_id = `<<some key>>`

Cuando estuviera listo para hacer la actualización, haría algo como esto donde usa la version en tu UPDATE y lanzar un error si la fila cambió

UPDATE addressTable
   SET address_line1 = `<<new address line 1>>`,
       city = `<<new city>>`,
       state = `<<new state>>`,
       zip = `<<new zip>>`,
       version = version + 1
 WHERE address_id = `<<some key>>`
   AND version = `<<version you read initially>>`

IF( SQL%ROWCOUNT = 0 )
THEN
  -- Darn.  The row must have changed since you read it.  Do something to
  -- alert the user.  Most likely, the application will need to re-query the
  -- data to see what the address has been changed to and then ask the user
  -- whether they want to re-apply the changes.
  RAISE_APPLICATION_ERROR( -20001, 'Oops, the row has changed since you read it.' );
END IF;

Su aplicación entonces haría algo útil con el error. Normalmente, eso significaría hacer algo como consultar los datos nuevamente, presentar los cambios al usuario y preguntarle si aún desea aplicar sus cambios. Si, por ejemplo, leo una dirección y empiezo a editarla, voy a almorzar, mi colega inicia sesión, lee la misma dirección, realiza algunas ediciones y la guarda, luego vuelvo e intento guardar mis cambios, generalmente tendría sentido para mostrarme algo que me dice que mi colega ya cambió la dirección a algo nuevo:¿quiero continuar haciendo cambios o quiero abandonarlos?