Estoy trabajando en un proyecto Spring-MVC en el que estoy usando Hibernate como ORM, PostgreSQL como nuestra base de datos y en uno de nuestros Objetos (GroupCanvas), tenemos un número que se incrementa cada vez que el usuario realiza alguna acción, y luego el El objeto GroupCanvas se actualiza en la base de datos y debe ser único.
El problema que tenemos actualmente es que, si varios usuarios toman medidas en el front-end, algunos de ellos obtienen números duplicados. Estamos trabajando para arreglar esto ahora, para que luego podamos implementar una secuencia y estar seguros de que los números son únicos.
¿Cómo puedo asegurarme de que cuando estoy actualizando la fila, otros usuarios estén esperando hasta que se actualice la fila? Probé LockMode.Pessimistic_write, y algunos otros, ninguno ayudó.
Código:
@Override public void incrementNoteCounterForGroupCanvas(int canvasId) { Session session = this.sessionFactory.getCurrentSession(); session.flush(); Query query = session.createQuery("update GroupCanvas as gc set gc.noteCount=gc.noteCount+1 where gc.mcanvasid=:canvasId"); query.setParameter("canvasId",canvasId); query.executeUpdate(); session.flush(); } @Override public GroupCanvas getCanvasById(int mcanvasid) { Session session = this.sessionFactory.getCurrentSession(); session.flush(); return (GroupCanvas) session.get(GroupCanvas.class, mcanvasid,LockMode.PESSIMISTIC_WRITE); } Ambos métodos están en DAO, que tiene anotación @Transactional y anotación presente en la capa de servicio también.
Gracias.
Mirando el método que ha publicado el uso si la técnica de 'BLOQUEO' no es del todo correcta. Para que un bloqueo termine con el resultado que está buscando, la secuencia de acciones debe ser similar a las siguientes (en pocas palabras, es similar al bloqueo de doble verificación pero implementado mediante bloqueos DB - https://en .wikipedia.org/wiki/Double-checked_locking ).
@Transactional en su método de servicio)@Transactional )La diferencia esencial de esta secuencia en comparación con el método publicado es que la actualización del valor de la propiedad se realiza mientras su transacción mantiene un bloqueo en la fila de entidad/base de datos de destino , lo que evita que otras transacciones lo lean mientras su actualización está en curso.
Espero que esto ayude .
ACTUALIZACIÓN: Creo que algo así como el siguiente fragmento de código debería funcionar como se esperaba:
@Transactional @Override public void incrementNoteCounterForGroupCanvas(int canvasId) { final Session session = this.sessionFactory.getCurrentSession(); final GroupCanvas groupCanvas = session.get(GroupCanvas.class, canvasId,LockMode.PESSIMISTIC_WRITE); session.refresh(groupCanvas); groupCanvas.setNoteCount(groupCanvas.getNoteCount()+1); session.saveOrUpdate(groupCanvas); session.flush(); }