Sus opciones son:
-
Ejecutar en
SERIALIZABLEaislamiento. Las transacciones interdependientes se anularán en el compromiso por tener una falla de serialización. Recibirá una gran cantidad de spam de registro de errores y hará muchos reintentos, pero funcionará de manera confiable. -
Defina un
UNIQUErestricción y vuelva a intentarlo en caso de falla, como anotó. Los mismos problemas que arriba. -
Si hay un objeto principal, puede
SELECT ... FOR UPDATEel objeto principal antes de hacer sumaxconsulta. En este caso,SELECT 1 FROM bar WHERE bar_id = $1 FOR UPDATE. Estás usandobarcomo candado para todos losfoos con esebar_id. Entonces puede saber que es seguro continuar, siempre que cada consulta que esté haciendo su incremento de contador lo haga de manera confiable. Esto puede funcionar bastante bien.Esto todavía hace una consulta agregada para cada llamada, lo cual (según la siguiente opción) es innecesario, pero al menos no envía spam al registro de errores como las opciones anteriores.
-
Usa una mesa de mostrador. Esto es lo que haría. Ya sea en
bar, o en una mesa auxiliar comobar_foo_counter, adquiera un ID de fila usandoUPDATE bar_foo_counter SET counter = counter + 1 WHERE bar_id = $1 RETURNING countero la opción menos eficiente si su marco no puede manejar
RETURNING:SELECT counter FROM bar_foo_counter WHERE bar_id = $1 FOR UPDATE; UPDATE bar_foo_counter SET counter = $1;Luego, en la misma transacción , use la fila de contador generada para el
number. Cuando confirmas, la fila de la tabla de contador para esebar_idse desbloquea para la próxima consulta a utilizar. Si retrocede, el cambio se descarta.
Recomiendo el enfoque de contador, usando una mesa auxiliar dedicada para el contador en lugar de agregar una columna a bar . Eso es más limpio de modelar y significa que creas menos actualizaciones en la bar , que puede ralentizar las consultas a bar .