Hola usuario de nuestro sitio web, descubrimos la respuesta a tu pregunta, desplázate y la encontrarás a continuación.
Solución:
Por lo general, no se recomienda el bloqueo pesimista y es muy costoso en términos de rendimiento en el lado de la base de datos. El problema que ha mencionado (la parte del código) algunas cosas no están claras, como:
- Si varios subprocesos acceden a su código al mismo tiempo.
- como estas creando
session
objeto (no estoy seguro si está usando Spring)?
Los objetos de sesión de Hibernate NO son seguros para subprocesos. Entonces, si hay varios subprocesos que acceden a la misma sesión e intentan actualizar la misma entidad de la base de datos, su código puede terminar en una situación de error como esta.
Entonces, lo que sucede aquí es que más de un subproceso intenta actualizar la misma entidad, un subproceso tiene éxito y cuando el siguiente subproceso va a confirmar los datos, ve que ya se modificó y termina arrojando StaleObjectStateException
.
EDITAR:
Hay una manera de usar Pessimistic Locking en Hibernate. Echa un vistazo a este enlace. Pero parece haber algún problema con este mecanismo. Sin embargo, me encontré con la publicación de un error en hibernación (HHH-5275). El escenario mencionado en el error es el siguiente:
Dos subprocesos están leyendo el mismo registro de la base de datos; uno de esos subprocesos debería usar el bloqueo pesimista bloqueando así el otro subproceso. Pero ambos subprocesos pueden leer el registro de la base de datos, lo que hace que la prueba falle.
Esto está muy cerca de lo que estás enfrentando. Intente esto si esto no funciona, la única forma en que se me ocurre es usar consultas SQL nativas donde puede lograr un bloqueo pesimista en la base de datos postgres con SELECT FOR UPDATE
consulta.
Sé que esta es una vieja pregunta, pero algunos de nosotros todavía la estamos respondiendo y miramos al cielo preguntándonos cómo. Aquí hay un tipo de problema que enfrenté.
Tenemos un administrador de colas que sondea los datos y los entrega a los controladores para que los procesen. Para evitar volver a seleccionar los mismos eventos, el administrador de colas bloquea el registro en la base de datos con un LOCKED
estado.
void poll()
record = dao.getLockedEntity();
queue(record);
este método no era transaccional pero dao.getLockedEntity()
era transaccional con REQUIRED
.
Todo bien y en el camino, después de unos meses en producción, falló con una excepción de bloqueo optimista.
Después de mucha depuración y verificación de detalles, podríamos descubrir que alguien ha cambiado el código de esta manera:
@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
void poll()
record = dao.getLockedEntity();
queue(record);
Entonces, el registro estaba en cola incluso antes de la transacción en dao.getLockedEntity()
se compromete (utiliza la misma transacción del método de encuesta) y los controladores (diferentes subprocesos) cambiaron el objeto debajo en el momento en que el poll()
la transacción del método se compromete.
Solucionamos el problema y ahora se ve bien.
Pensé en compartirlo porque las excepciones de bloqueo optimista pueden ser confusas y difíciles de depurar. Alguien podría beneficiarse de mi experiencia.
Saludos, Lyju
No parece que en realidad esté utilizando el correo electrónico que recupera de la base de datos, sino una copia anterior que obtiene como parámetro. Lo que sea que se esté utilizando para el control de versiones en la fila ha cambiado entre el momento en que se recuperó la versión anterior y el momento en que realiza la actualización.
Probablemente quieras que tu código se parezca más a:
@Transactional
public void test(String id, String subject)
Email email = getEmailById(id);
email.setSubject(subject);
updateEmail(email);
Comentarios y puntuaciones del tutorial
Nos puedes proteger nuestra misión fijando un comentario y dejando una puntuación te damos la bienvenida.