sql >> Base de Datos >  >> RDS >> PostgreSQL

ACTUALIZACIÓN atómica .. SELECCIONAR en Postgres

Si bien la sugerencia de Erwin es posiblemente la más simple forma de obtener el comportamiento correcto (siempre que vuelva a intentar su transacción si obtiene una excepción con SQLSTATE de 40001), las aplicaciones de cola, por su naturaleza, tienden a funcionar mejor con el bloqueo de solicitudes para tener la oportunidad de tomar su turno en la cola que con la implementación de PostgreSQL de SERIALIZABLE transacciones, lo que permite una mayor concurrencia y es algo más "optimista" sobre las posibilidades de colisión.

La consulta de ejemplo en la pregunta, tal como está, en el valor predeterminado READ COMMITTED el nivel de aislamiento de transacciones permitiría que dos (o más) conexiones simultáneas "reclamen" la misma fila de la cola. Lo que sucederá es esto:

  • T1 comienza y llega a bloquear la fila en UPDATE fase.
  • T2 se superpone a T1 en tiempo de ejecución e intenta actualizar esa fila. Bloquea pendiente del COMMIT o ROLLBACK de T1.
  • T1 confirma, habiendo "reclamado" con éxito la fila.
  • T2 intenta actualizar la fila, descubre que T1 ya la tiene, busca la nueva versión de la fila, descubre que aún cumple con los criterios de selección (que es solo ese id coincidencias), y también "reclama" la fila.

Se puede modificar para que funcione correctamente (si está utilizando una versión de PostgreSQL que permite FOR UPDATE cláusula en una subconsulta). Simplemente agregue FOR UPDATE hasta el final de la subconsulta que selecciona el id, y sucederá esto:

  • T1 comienza y ahora bloquea la fila antes de seleccionar la identificación.
  • T2 se superpone a T1 en el tiempo de ejecución y se bloquea al intentar seleccionar una identificación, pendiente del COMMIT o ROLLBACK de T1.
  • T1 confirma, habiendo "reclamado" con éxito la fila.
  • Para cuando T2 sea capaz de leer la fila para ver la identificación, ve que se ha reclamado, por lo que encuentra la siguiente identificación disponible.

En la REPEATABLE READ o SERIALIZABLE nivel de aislamiento de transacción, el conflicto de escritura generaría un error, que podría detectar y determinar que era un error de serialización basado en SQLSTATE, y volver a intentarlo.

Si por lo general desea transacciones SERIALIZABLES pero desea evitar reintentos en el área de la cola, puede lograrlo utilizando un bloqueo de aviso.