Una forma de hacer frente a los interbloqueos es tener un mecanismo de reintento que espere un intervalo aleatorio e intente ejecutar la transacción nuevamente. El intervalo aleatorio es necesario para que las transacciones en colisión no sigan chocando continuamente entre sí, causando lo que se llama un bloqueo en vivo, algo aún más desagradable de depurar. En realidad, la mayoría de las aplicaciones complejas necesitarán un mecanismo de reintento de este tipo tarde o temprano cuando necesiten manejar fallas en la serialización de transacciones.
Por supuesto, si puede determinar la causa del interbloqueo, generalmente es mucho mejor eliminarlo o lo hará. volver a morderte. En casi todos los casos, incluso cuando la condición de interbloqueo es rara, vale la pena el poco rendimiento y la sobrecarga de codificación para obtener los bloqueos en un orden determinista u obtener bloqueos más gruesos para evitar el gran golpe ocasional de latencia y el repentino acantilado de rendimiento. al escalar la concurrencia.
Cuando recibe constantemente dos sentencias INSERT bloqueadas, lo más probable es que se trate de un problema de orden de inserción de índice único. Pruebe, por ejemplo, lo siguiente en dos ventanas de comando psql:
Thread A | Thread B
BEGIN; | BEGIN;
| INSERT uniq=1;
INSERT uniq=2; |
| INSERT uniq=2;
| block waiting for thread A to commit or rollback, to
| see if this is an unique key error.
INSERT uniq=1; |
blocks waiting |
for thread B, |
DEADLOCK |
V
Por lo general, el mejor curso de acción para resolver esto es descubrir los objetos principales que protegen todas esas transacciones. La mayoría de las aplicaciones tienen una o dos entidades primarias, como usuarios o cuentas, que son buenas candidatas para esto. Luego, todo lo que necesita es que cada transacción obtenga los bloqueos en la entidad principal que toca a través de SELECCIONAR ... PARA ACTUALIZAR. O si toca varios, obtenga bloqueos en todos ellos pero en el mismo orden cada vez (el orden por clave principal es una buena opción).