Estoy usando un PostUpdateEventListener registrado a través de

registry.appendListeners(EventType.POST_COMMIT_UPDATE, listener)

Y algunos otros oyentes para realizar un seguimiento de los cambios realizados por Hibernate. Esto funciona perfectamente, sin embargo, veo un problema allí:

Digamos, para rastrear algunos amount por id, simplemente ejecuto

 amountByIdConcurrentMap.put(id, amount);

En cada POST_COMMIT_UPDATE (ignoremos otras operaciones). El problema es que esta llamada ocurre algún tiempo después de la confirmación . Entonces, con dos confirmaciones escribiendo la misma entidad poco después de la otra, puedo recibir los eventos en el orden incorrecto , terminando con el amount anterior almacenado.

  • ¿Es esto realmente posible o las operaciones están sincronizadas de alguna manera?
  • ¿Hay alguna forma de prevenir o al menos detectar tal situación?
5
maaartinus 13 nov. 2017 a las 00:48

2 respuestas

La mejor respuesta

Dos preguntas y una propuesta después

  1. ¿Está seguro de que necesita esta optimización? ¿Por qué no buscar la cantidad tal como está escrita en la base de datos consultando allí? Lo que le da motivos para trabajar con el almacenamiento en caché.

  2. ¿Cómo se asegura de que el cálculo de la cantidad antes de escribirlo en la base de datos esté correctamente sincronizado, de modo que varios subprocesos o probablemente nodos no utilicen datos antiguos para calcular la cantidad y, por lo tanto, sobrescriban el resultado de un cálculo posterior?

Supongo que manejas bien la pregunta número 2. Entonces tienes opciones:

  1. Bloqueo pesimista, eso significa que inmediatamente antes de la confirmación puede actualizar exclusivamente su caché sin problemas de concurrencia.
  2. Bloqueo optimista: en ese caso, tiene una especie de marca de tiempo o contador en su registro de base de datos que también puede poner en la caché junto con la cantidad. Puede utilizar este valor para averiguar cuál es el valor más reciente.
2
aschoerk 15 nov. 2017 a las 22:30

No, no hay garantías de pedidos, por lo que deberá asegurarse de garantizar una sincronización adecuada manualmente.

Si el problema real que está resolviendo es el almacenamiento en caché del estado de la entidad y si es adecuado utilizar la caché de segundo nivel para la entidad en cuestión, entonces obtendría todo lo que necesita al habilitar la caché L2.

De lo contrario, en lugar de actualizar el mapa directamente desde los oyentes de actualización, podría enviar tareas a un Ejecutor o sistema de mensajería que iniciaría de forma asincrónica una nueva transacción y select for update la cantidad para el ID dado de la base de datos. Luego, actualice el mapa en la misma transacción mientras mantiene el bloqueo de fila correspondiente en la base de datos, de modo que las actualizaciones del mapa para la misma identificación se realicen en serie.

2
Dragan Bozanovic 15 nov. 2017 a las 21:17