2010-07-01 17 views
13

Estoy obteniendo esta excepción en un controlador de una aplicación web basada en Spring framework que utiliza hibernate. He intentado muchas formas de contrarrestar esto, pero no pude resolverlo.La fila StaleObjectstateException fue actualizada o eliminada por

En el método del controlador, handleRequestInternal, hay llamadas realizadas a la base de datos principalmente para 'leer', a menos que sea una acción de envío. He estado usando Spring's Session, pero me moví al getHibernateTemplate() y el problema persiste.

básicamente, esta es la segunda llamada a la base de datos que arroja esta excepción. Es decir:

1) getEquipmentsByNumber(number) {primero se obtiene un equipo de la base de datos en función del 'número', que tiene una lista de propiedades y cada propiedad tiene una lista de valores. Me bucle a través de esos valores (objetos primitivos cadenas) que se lee en las variables)

2) getMaterialById(id) {recupera materiales a base de id}

entiendo que la segunda llamada, lo más probable, es hacer que la sesión "Flush", pero solo estoy "leyendo" objetos, entonces ¿por qué la segunda llamada arroja la excepción de estado obsoleto del objeto en la propiedad del Equipo si no hay cambios?

No puedo borrar la caché después de la llamada ya que causa LazyExceptions en los objetos que paso a la vista.

He leído esto: https://forums.hibernate.org/viewtopic.php?f=1&t=996355&start=0 pero no he podido resolver el problema en función de las sugerencias proporcionadas.

¿Cómo puedo resolver este problema? Cualquier idea y pensamiento son apreciados.

ACTUALIZACIÓN: Lo que acabo de probar es que en la función getEquipmentsByNumber() después de leer las variables de la lista de propiedades, hago esto: getHibernateTemplate().flush(); y ahora la excepción es en esta línea en lugar de la llamada a buscar el material (que es getMaterialById(id)).

ACTUALIZACIÓN: Antes de llamar explícitamente al ras, estoy quitando el objeto de caché de sesión para que ningún objeto rancio permanece en la memoria caché.

getHibernateTemplate().evict(equipment); 
getHibernateTemplate().flush(); 

Bien, ahora el problema se ha movido a la siguiente obtención de DB después de que hice esto. ¡Supongo que tengo que etiquetar los métodos como sincronizados y expulsar los Objetos tan pronto como termine de leer sus contenidos! no suena muy bien

ACTUALIZACIÓN: Método handleRequestInternal "sincronizado". El error desapareció Por supuesto, no es la mejor solución, pero ¡qué hacer! Probé en handleRequestInternal para cerrar la sesión actual y abrir una nueva. Pero haría que otras partes de la aplicación no funcionen correctamente. Intenté usar ThreadLocal que tampoco funcionó.

+1

si pudiera publicar el código para el método que arroja la excepción, lo analizaré más a fondo. Suena como algo sospechoso – walnutmon

Respuesta

0

Este problema fue algo que experimenté y fue bastante frustrante, aunque tiene que haber algo extraño sucediendo en sus llamadas DAO/Hibernate, porque si está haciendo una búsqueda por ID no hay ninguna razón para obtener un estado obsoleto, ya que es solo una simple búsqueda de un objeto.

En primer lugar, asegúrese de que todos sus métodos son anotados con @Transaction(required=true) // you'll have to look up the exact syntax

Sin embargo, esta excepción es generalmente inicia cuando se intenta realizar cambios en un objeto que ha sido separado de la sesión se recupera de. La solución a esto a menudo no es simple y requeriría más código publicado para que podamos ver exactamente lo que está sucediendo; Mi sugerencia general sería crear un @Service que realice este tipo de cosas en una sola transacción

+0

Gracias por la sugerencia. Lo que acabo de probar es que en la función getEquipmentsByNumber después de leer las variables de la lista de propiedades, hago esto: getHibernateTemplate(). Flush(); y ahora la excepción está en esta línea en lugar de la llamada para recuperar material (es decir getMaterialById (id)) No estoy usando anotaciones ya que no estoy muy familiarizado con ella. – Saky

2

Aquí hay 3 posibilidades (como no sé exactamente, qué tipo de sesión de hibernación está manejando). Agregue uno después de otro y pruebe:

Utilice el mapeo bidireccional con inverse=true entre el objeto principal y el objeto secundario, para que el cambio en el elemento primario o secundario se propague al otro extremo de la relación correctamente.

Añadir soporte para bloqueo optimista usando TimeStamp o Version columna

Uso consulta de combinación a buscar todo el gráfico de objetos [+ padres los niños] juntos para evitar la segunda llamada por completo.

Por último, si y sólo si nada funciona: Cargar el padre de nuevo por Id (usted tiene que ya) y rellenar los datos modificados a continuación, actualizar.

¡La vida será buena! :)

+0

Creo que la sugerencia de usar el inverso es probablemente confusa en el contexto de la propagación de cambios de padres a hijos. Para esto, el comportamiento real de configurar es "en cascada". Inverso como concepto es ortogonal a la cascada – Shailendra

3

También he estado luchando con esta excepción, pero cuando continuó recurriendo incluso cuando puse un candado en el objeto (y en un entorno de prueba, donde sabía que era el único proceso tocando el objeto), Decidí dar al paréntesis en el seguimiento de la pila su debida consideración.

org.hibernate.StaleObjectStateException: Fila se actualiza o se elimina por otra transacción (o mapeo no salva-valor era incorrecta): [com.rc.model.mexp.MerchantAccount # 59132]

En nuestro caso, resultó que el mapeo era incorrecto; Tuvimos type="text" en el mapeo de un campo que era un tipo de texto medio en la base de datos, y parece que Hibernate realmente lo odia, al menos bajo ciertas circunstancias. Eliminamos por completo la especificación de tipo de la asignación para este campo y el problema se resolvió.

Ahora, lo extraño es que en nuestro entorno de producción, con el supuesto mapeo problemático implementado, NO obtenemos esta excepción. ¿Alguien tiene alguna idea de por qué esto podría ser? Estamos utilizando la misma versión de MySQL - "5.0.22-log" (no sé lo que significa "-log") en envs de desarrollo y producción.

5

Usted es mis-Hibernate utilizando de alguna manera que hace que se creen que eres actualizar o borrar objetos de la base de datos.

Es por eso que llamar al flush() está arrojando una excepción.

Una posibilidad: que está "compartiendo" Sesión o Entidades incorrectamente, a través de los campos de miembro de su servlet o controlador. Esta es la razón principal por la que 'sincronizado' cambiará los síntomas de error. Solución corta: nunca haga esto. Las sesiones y las entidades no deben funcionar de esta manera: cada solicitud debe procesarse de manera independiente.

Otra posibilidad: unsaved-value se predetermina a 0 para los campos PK "int". En su lugar, puede escribirlos como "Entero", si realmente desea usar 0 como valor PK válido.

tercera sugerencia: uso Session de Hibernate explícitamente, aprender a escribir código correcto simple que funciona, a continuación, cargar la fuente de Java para las bibliotecas/Spring Hibernate para que pueda leer & entender lo que estas bibliotecas están haciendo en realidad para usted.

Cuestiones relacionadas