Error de hibernación: org.hibernate.NonUniqueObjectException: un objeto diferente con el mismo valor de identificador ya estaba asociado con la sesión

114

Tengo dos Objetos de usuario y mientras trato de guardar el objeto usando

session.save(userObj);

Estoy teniendo el siguiente error:

Caused by: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:
[com.pojo.rtrequests.User#com.pojo.rtrequests.User@d079b40b]

Estoy creando la sesión usando

BaseHibernateDAO dao = new BaseHibernateDAO();          

rtsession = dao.getSession(userData.getRegion(),
                           BaseHibernateDAO.RTREQUESTS_DATABASE_NAME);

rttrans = rtsession.beginTransaction();
rttrans.begin();

rtsession.save(userObj1);
rtsession.save(userObj2);

rtsession.flush();
rttrans.commit();

rtsession.close(); // in finally block

También intenté hacer lo session.clear()antes de guardar, todavía sin suerte.

Esta es la primera vez que obtengo el objeto de sesión cuando llega una solicitud de usuario, así que entiendo por qué dice que el objeto está presente en la sesión.

¿Alguna sugerencia?

duro
fuente
Aquí hay otro hilo maravilloso que ayudó a resolver mi problema getj2ee.over-blog.com/…
Reddymails

Respuestas:

173

He tenido este error muchas veces y puede ser bastante difícil de localizar ...

Básicamente, lo que hibernate está diciendo es que tienes dos objetos que tienen el mismo identificador (la misma clave primaria) pero no son el mismo objeto.

Le sugiero que analice su código, es decir, comente los bits hasta que desaparezca el error y luego vuelva a colocar el código hasta que vuelva y encuentre el error.

La mayoría de las veces ocurre a través de guardados en cascada donde hay un guardado en cascada entre el objeto A y B, pero el objeto B ya se ha asociado con la sesión pero no está en la misma instancia de B que el de A.

¿Qué generador de claves primarias estás usando?

La razón por la que pregunto es que este error está relacionado con cómo le está diciendo a Hibernate que determine el estado persistente de un objeto (es decir, si un objeto es persistente o no). El error podría estar ocurriendo porque hibernate está tratando de persistir un objeto que ya es persistente. De hecho, si usa save hibernate intentará persistir ese objeto, y tal vez ya exista un objeto con esa misma clave primaria asociada con la sesión.

Ejemplo

Suponiendo que tiene un objeto de clase de hibernación para una tabla con 10 filas basadas en una combinación de clave principal (columna 1 y columna 2). Ahora, ha eliminado 5 filas de la tabla en algún momento. Ahora, si intenta agregar las mismas 10 filas nuevamente, mientras hibernate intenta persistir los objetos en la base de datos, se agregarán 5 filas que ya fueron eliminadas sin errores. Ahora, las 5 filas restantes que ya existen, lanzarán esta excepción.

Entonces, el enfoque fácil sería verificar si ha actualizado / eliminado algún valor en una tabla que es parte de algo y luego está tratando de insertar los mismos objetos nuevamente

Michael Wiles
fuente
4
Buena respuesta². La clave principal fue mi problema, resuelto con GeneratedValue configurando una secuencia para postgresql.
Rodrigo Ferrari
2
Tuve el mismo problema. En mi caso, tuve un objeto buscado en un código e intenté construir un nuevo objeto con la misma ID en otra pieza de código mientras el primer objeto aún estaba en la sesión de hibernación.
dellasavia
18

Este es solo un punto en el que la hibernación crea más problemas de los que resuelve. En mi caso hay muchos objetos con el mismo identificador 0, porque son nuevos y no tienen uno. La base de datos los genera. En algún lugar he leído que las señales 0 no están configuradas. La forma intuitiva de mantenerlos es iterar sobre ellos y decir hibernar para guardar los objetos. Pero no puedes hacer eso - "Por supuesto que debes saber que la hibernación funciona de esta y de esa manera, por lo tanto tienes que ..." Así que ahora puedo intentar cambiar los ID a Long en lugar de long y ver si funciona. Al final, es más fácil hacerlo con un simple mapeador por su cuenta, porque la hibernación es solo una carga intransparente adicional. Otro ejemplo: intentar leer los parámetros de una base de datos y conservarlos en otra le obliga a hacer casi todo el trabajo manualmente.

Hein
fuente
13
Odio la hibernación también ... y las bases de datos ... Después de todos los problemas que me causaron supongo que es más fácil usar un archivo de texto (estoy bromeando, pero aún así ...).
Igor Popov
En mi caso hay muchos objetos con el mismo identificador 0, porque son nuevos y no tienen uno. La base de datos los genera. En algún lugar he leído que las señales 0 no están configuradas. La forma intuitiva de mantenerlos es iterar sobre ellos y decir hibernar para guardar los objetos . Necesito hacer exactamente esto. ¿Podría decirme cuál es la "forma de hibernación" para hacer esto?
Ramsés
En mi caso, tuve que usar session.merge (myobject) ya que tenía dos instancias de este objeto. Por lo general, eso sucede cuando una entidad persiste y se separa de la sesión. Se solicita otra instancia de esta entidad para hibernar. Esta segunda instancia quedó pegada a la sesión. Se modifica la primera instancia. Más en getj2ee.over-blog.com/…
Reddymails
no es hibernación haciendo problemas, sino falta de comprensión de cómo funciona
ACV
17

UTILIZAR session.evict(object);La función de evict()método se utiliza para eliminar la instancia de la caché de sesión. Entonces, por primera vez al guardar el objeto, guarde el objeto llamando al session.save(object)método antes de desalojar el objeto de la caché. De la misma manera, actualice el objeto llamando session.saveOrUpdate(object)o session.update(object)antes de llamar a evict ().

Rahul N
fuente
11

Esto puede suceder cuando ha utilizado el mismo objeto de sesión para lectura y escritura. ¿Cómo? Digamos que ha creado una sesión. Ha leído un registro de la tabla de empleados con la clave primaria Emp_id = 101 Ahora ha modificado el registro en Java. Y va a guardar el registro del empleado en la base de datos. no hemos cerrado sesión en ningún lugar aquí. Como el objeto que se leyó también persiste en la sesión. Entra en conflicto con el objeto que deseamos escribir. De ahí viene este error.

Prashant Bari
fuente
9

Como alguien ya señaló anteriormente, me encontré con este problema cuando tenía cascade=allen ambos extremos de una one-to-manyrelación, así que supongamos A -> B (uno a muchos de A y muchos a uno de B) y estaba actualizando la instancia de B en A y luego llamando a saveOrUpdate (A), resultó en una solicitud de guardado circular, es decir, guardar de A desencadena guardar de B que desencadena guardar de A ... y en la tercera instancia cuando se intentó la entidad (de A) Al agregarse al sessionPersistenceContext, se lanzó la excepción duplicateObject.
  Podría resolverlo quitando la cascada de un extremo.

redzedi
fuente
Resolvió mi problema junto con stackoverflow.com/questions/4334970/…
Magno C
5

Puede usar session.merge(obj), si está guardando con diferentes sesiones con el mismo identificador de objeto persistente.
Funcionó, tuve el mismo problema antes.

Pavan Kumar
fuente
4

También encontré este problema y me costó encontrar el error.

El problema que tuve fue el siguiente:

El objeto ha sido leído por un Dao con una sesión de hibernación diferente.

Para evitar esta excepción, simplemente vuelva a leer el objeto con el dao que guardará / actualizará este objeto más adelante.

entonces:

class A{      

 readFoo(){
       someDaoA.read(myBadAssObject); //Different Session than in class B
    }

}

class B{



 saveFoo(){
       someDaoB.read(myBadAssObjectAgain); //Different Session than in class A
       [...]
       myBadAssObjectAgain.fooValue = 'bar';
       persist();
    }

}

¡Espero que algunas personas ahorren mucho tiempo!

Frithjof
fuente
4

Me encontré con este problema por:

  1. Eliminar un objeto (usando HQL)
  2. Almacenamiento inmediato de un nuevo objeto con la misma identificación

Lo resolví vaciando los resultados después de la eliminación y borrando el caché antes de guardar el nuevo objeto

String delQuery = "DELETE FROM OasisNode";
session.createQuery( delQuery ).executeUpdate();
session.flush();
session.clear();
wbdarby
fuente
4

Este problema ocurre cuando actualizamos el mismo objeto de sesión, que hemos utilizado para buscar el objeto de la base de datos.

Puede utilizar el método de fusión de hibernación en lugar del método de actualización.

Por ejemplo, primero use session.get () y luego puede usar session.merge (object). Este método no creará ningún problema. También podemos usar el método merge () para actualizar el objeto en la base de datos.

Jayendra Birtharia
fuente
3

Obtenga el objeto dentro de la sesión, aquí un ejemplo:

MyObject ob = null;
ob = (MyObject) session.get(MyObject.class, id);
sock_osg
fuente
3
Buen intento, pero el objeto "ob" se devuelve sin los datos actualizados (considerando que se actualizó a través de la aplicación durante el tiempo de ejecución, entre los objetos recuperados de la base de datos y su guardado).
Alex
2

¿Son correctas sus asignaciones de identificación? Si la base de datos es responsable de crear el Id a través de un identificador, debe asignar su objeto de usuario a eso.

cwap
fuente
2

Encontré este problema al eliminar un objeto, ni el desalojo ni el borrado ayudaron.

/**
 * Deletes the given entity, even if hibernate has an old reference to it.
 * If the entity has already disappeared due to a db cascade then noop.
 */
public void delete(final Object entity) {
  Object merged = null;
  try {
    merged = getSession().merge(entity);
  }
  catch (ObjectNotFoundException e) {
    // disappeared already due to cascade
    return;
  }
  getSession().delete(merged);
}
TimP
fuente
2

antes de la posición donde comienzan los objetos repetitivos, debe cerrar la sesión y luego debe comenzar una nueva sesión

session.close();      
session = HibernateUtil.getSessionFactory().openSession();

por lo que de esta forma en una sesión no hay más de una entidad que tenga el mismo identificador.

engtuncay
fuente
2

Llega tarde a la fiesta, pero puede ayudar a los futuros usuarios.

Tengo este problema cuando selecciono un registro usando getsession() y nuevamente actualizo otro registro con el mismo identificador usando la misma sesión que causa el problema. Código agregado a continuación.

Customer existingCustomer=getSession().get(Customer.class,1);
Customer customerFromUi;// This customer details comiong from UI with identifer 1

getSession().update(customerFromUi);// Here the issue comes

Esto nunca debería hacerse. La solución es desalojar la sesión antes de actualizar o cambiar la lógica empresarial.

vipin cp
fuente
1

Compruebe si olvidó poner @GenerateValue para la columna @Id. Tuve el mismo problema con la relación de muchos a muchos entre Película y Género. El programa arrojó Hibernate Error: org.hibernate.NonUniqueObjectException: un objeto diferente con el mismo valor de identificador ya estaba asociado con el error de sesión. Más tarde descubrí que solo tengo que asegurarme de que tienes @GenerateValue en el método de obtención de GenreId.

Thupten
fuente
¿Cómo puedo aplicar su solución a mi pregunta? ¿Puedo crear una columna de identificación en la clase de tarea? stackoverflow.com/questions/55732955/…
sbattou
1

solo verifique la identificación si toma nulo o 0 como

if(offersubformtwo.getId()!=null && offersubformtwo.getId()!=0)

en agregar o actualizar donde el contenido se establece de formulario a Pojo

Ayan Sarkar
fuente
1

Soy nuevo en NHibernate, y mi problema fue que usé una sesión diferente para consultar mi objeto que la que usé para guardarlo. Entonces, la sesión de ahorro no sabía sobre el objeto.

Parece obvio, pero al leer las respuestas anteriores, estaba buscando 2 objetos en todas partes, no 2 sesiones.

DustinA
fuente
1

@GeneratedValue (estrategia = GenerationType.IDENTITY), agregar esta anotación a la propiedad de clave primaria en su bean de entidad debería resolver este problema.

Arrendajo
fuente
1

Resolví este problema.
En realidad, esto está sucediendo porque olvidamos la implementación del tipo de generador de la propiedad PK en la clase bean. Así que hazlo de cualquier tipo como

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;

cuando persistimos los objetos de bean, cada objeto adquirió la misma ID, por lo que el primer objeto se guarda, cuando otro objeto persiste, luego HIB FW a través de este tipo de Exception: org.hibernate.NonUniqueObjectException:un objeto diferente con el mismo valor de identificador ya estaba asociado con la sesión.

Ankit Sharma
fuente
1

El problema ocurre porque en la misma sesión de hibernación está tratando de guardar dos objetos con el mismo identificador. Hay dos soluciones: -

  1. Esto sucede porque no ha configurado su archivo mapping.xml correctamente para los campos de identificación como se muestra a continuación:

    <id name="id">
      <column name="id" sql-type="bigint" not-null="true"/>
      <generator class="hibernateGeneratorClass"</generator>
    </id>
  2. Sobrecargue el método getsession para aceptar un parámetro como isSessionClear y borre la sesión antes de devolver la sesión actual como se muestra a continuación

    public static Session getSession(boolean isSessionClear) {
        if (session.isOpen() && isSessionClear) {
            session.clear();
            return session;
        } else if (session.isOpen()) {
            return session;
        } else {
            return sessionFactory.openSession();
        }
    }

Esto hará que los objetos de sesión existentes se borren e incluso si hibernación no genera un identificador único, suponiendo que haya configurado su base de datos correctamente para una clave primaria usando algo como Auto_Increment, debería funcionar para usted.

Rahul Kumar
fuente
1

Tuve un problema similar. En mi caso, me había olvidado de establecer el increment_byvalor en la base de datos para que fuera el mismo que el utilizado por cache_sizey allocationSize. (Las flechas apuntan a los atributos mencionados)

SQL:

CREATED         26.07.16
LAST_DDL_TIME   26.07.16
SEQUENCE_OWNER  MY
SEQUENCE_NAME   MY_ID_SEQ
MIN_VALUE       1
MAX_VALUE       9999999999999999999999999999
INCREMENT_BY    20 <-
CYCLE_FLAG      N
ORDER_FLAG      N
CACHE_SIZE      20 <-
LAST_NUMBER     180

Java:

@SequenceGenerator(name = "mySG", schema = "my", 
sequenceName = "my_id_seq", allocationSize = 20 <-)
kaba713
fuente
1

De lo contrario a lo que dijo wbdarby , incluso puede suceder cuando se busca un objeto dando el identificador del objeto a un HQL. En el caso de intentar modificar los campos del objeto y guardarlo nuevamente en la base de datos (la modificación podría ser insertar, eliminar o actualizar) en la misma sesión , aparecerá este error. Intente borrar la sesión de hibernación antes de guardar su objeto modificado o cree una nueva sesión.

Espero haber ayudado ;-)

Arash moradabadi
fuente
1

Tengo el mismo error que estaba reemplazando mi Set con uno nuevo de Jackson.

Para resolver esto, mantengo el conjunto existente, elimino del conjunto antiguo el elemento desconocido en la nueva lista con retainAll. Luego agrego los nuevos con addAll.

    this.oldSet.retainAll(newSet);
    this.oldSet.addAll(newSet);

No es necesario tener la sesión y manipularla.

Ôrel
fuente
1

Prueba esto. ¡Lo siguiente funcionó para mí!

En el hbm.xmlarchivo

  1. Necesitamos establecer el dynamic-updateatributo de la etiqueta de clase en true:

    <class dynamic-update="true">
  2. Establezca el atributo de clase de la etiqueta del generador en la columna única en identity:

    <generator class="identity">

Nota: establezca la columna única en en identitylugar de assigned.

RaGa__M
fuente
0

Otra cosa que funcionó para mí fue hacer que la variable de instancia Long en lugar de long


Tenía mi identificación larga de la variable de clave principal; cambiarlo a Long id; trabajó

Todo lo mejor


fuente
0

Siempre puedes hacer una descarga de sesión. Flush sincronizará el estado de todos sus objetos en sesión (por favor, alguien me corrija si me equivoco), y tal vez resuelva su problema en algunos casos.

La implementación de sus propios iguales y código hash también puede ayudarlo.

caarlos0
fuente
0

Puede comprobar su configuración de cascada. La configuración de Cascade en sus modelos podría estar causando esto. Eliminé la configuración de cascada (esencialmente no permite las inserciones / actualizaciones de cascada) y esto resolvió mi problema

usuario1609848
fuente
0

También encontré este error. Lo que funcionó para mí es asegurarme de que la clave principal (que se genera automáticamente) no sea un PDT (es decir, largo, int, ect.), Sino un objeto (es decir, Long, Integer, etc.)

Cuando cree su objeto para guardarlo, asegúrese de pasar nulo y no 0.

Jaco Van Niekerk
fuente
0

¿Esto ayuda?

User userObj1 = new User();
User userObj2 = userObj1;
.
.
.
rtsession.save(userObj1);
rtsession.save(userObj2); 
George Papatheodorou
fuente
0

He resuelto un problema similar como ese:

plan = (FcsRequestPlan) session.load(plan.getClass(), plan.getUUID());
while (plan instanceof HibernateProxy)
    plan = (FcsRequestPlan) ((HibernateProxy) plan).getHibernateLazyInitializer().getImplementation();
usuario3132194
fuente