Hibernate Error: org.hibernate.NonUniqueObjectException: un oggetto diverso con lo stesso valore identificativo era già associato alla sessione


114

Ho due oggetti utente e mentre provo a salvare l'oggetto usando

session.save(userObj);

Ricevo il seguente errore:

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]

Sto creando la sessione 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

Ho anche provato a fare il session.clear()salvataggio prima, ancora senza fortuna.

Questo è per la prima volta che ricevo l'oggetto sessione quando arriva una richiesta dell'utente, quindi sto capendo perché sta dicendo che l'oggetto è presente nella sessione.

Eventuali suggerimenti?


Ecco un altro meraviglioso thread che ha aiutato a risolvere il mio problema getj2ee.over-blog.com/…
Reddymails

Risposte:


173

Ho riscontrato questo errore molte volte e può essere abbastanza difficile da rintracciare ...

Fondamentalmente, ciò che sta dicendo hibernate è che hai due oggetti che hanno lo stesso identificatore (stessa chiave primaria) ma non sono lo stesso oggetto.

Ti suggerirei di scomporre il tuo codice, cioè commentare i bit fino a quando l'errore non scompare e quindi rimettere il codice fino a quando non ritorna e dovresti trovare l'errore.

Molto spesso avviene tramite salvataggi a cascata dove c'è un salvataggio a cascata tra l'oggetto A e B, ma l'oggetto B è già stato associato alla sessione ma non si trova sulla stessa istanza di B di quello su A.

Quale generatore di chiavi primarie stai usando?

Il motivo per cui chiedo è che questo errore è correlato al modo in cui stai dicendo a hibernate di accertare lo stato persistente di un oggetto (cioè se un oggetto è persistente o meno). L'errore potrebbe verificarsi perché l'ibernazione sta tentando di rendere persistente un oggetto che è già persistente. Infatti, se usi save hibernate proverai a mantenere quell'oggetto, e forse c'è già un oggetto con la stessa chiave primaria associata alla sessione.

Esempio

Supponendo che tu abbia un oggetto classe di ibernazione per una tabella con 10 righe in base a una combinazione di chiavi primarie (colonna 1 e colonna 2). Ora, hai rimosso 5 righe dalla tabella ad un certo punto del tempo. Ora, se provi ad aggiungere nuovamente le stesse 10 righe, mentre l'ibernazione cerca di rendere persistenti gli oggetti nel database, 5 righe che erano già state rimosse verranno aggiunte senza errori. Ora le restanti 5 righe già esistenti genereranno questa eccezione.

Quindi l'approccio semplice sarebbe controllare se hai aggiornato / rimosso qualsiasi valore in una tabella che fa parte di qualcosa e in seguito stai cercando di inserire di nuovo gli stessi oggetti


4
Bella risposta². La chiave primaria era il mio problema, risolto con GeneratedValue impostando una sequenza per postgresql.
Rodrigo Ferrari

2
Ho avuto lo stesso problema. Nel mio caso, ho cercato un oggetto in un codice e ho provato a creare un nuovo oggetto con lo stesso ID in un'altra porzione di codice mentre il primo oggetto era ancora in una sessione di ibernazione.
dellasavia

18

Questo è solo un punto in cui l'ibernazione crea più problemi di quanti ne risolva. Nel mio caso ci sono molti oggetti con lo stesso identificatore 0, perché sono nuovi e non ne hanno uno. Il db li genera. Da qualche parte ho letto che 0 segnali Id non impostato. Il modo intuitivo per mantenerli è iterarli su di essi e dire ibernazione per salvare gli oggetti. Ma non puoi farlo - "Ovviamente dovresti sapere che l'ibernazione funziona in questo e in quel modo, quindi devi .." Quindi ora posso provare a cambiare Ids in Long invece che long e vedere se funziona. Alla fine è più facile farlo con un semplice mappatore da solo, perché l'ibernazione è solo un ulteriore fardello intrasparente. Un altro esempio: provare a leggere i parametri da un database e mantenerli in un altro ti costringe a fare quasi tutto il lavoro manualmente.


13
Odio anche l'ibernazione ... e le banche dati ... Dopo tutti i problemi che mi hanno causato immagino sia più facile usare un file di testo (sto scherzando, ma comunque ...).
Igor Popov

Nel mio caso ci sono molti oggetti con lo stesso identificatore 0, perché sono nuovi e non ne hanno uno. Il db li genera. Da qualche parte ho letto che 0 segnali Id non impostato. Il modo intuitivo per mantenerli è iterarli e dire ibernazione per salvare gli oggetti . Devo fare esattamente questo. Potresti dirmi qual è il "modo ibernato" per farlo?
Ramses

Nel mio caso ho dovuto utilizzare session.merge (myobject) poiché avevo due istanze di questo oggetto, di solito ciò accade quando un'entità viene mantenuta e scollegata dalla sessione. Viene richiesto di ibernare un'altra istanza di questa entità. Questa seconda istanza è rimasta attaccata alla sessione. La prima istanza viene modificata. Maggiori informazioni su getj2ee.over-blog.com/…
Reddymails

non è ibernazione che crea problemi, ma mancanza di comprensione di come funziona
ACV

17

USe session.evict(object);La funzione di evict()metodo viene utilizzata per rimuovere l'istanza dalla cache della sessione. Quindi, per la prima volta che salvi l'oggetto, salva l'oggetto chiamando il session.save(object)metodo prima di rimuovere l'oggetto dalla cache. Allo stesso modo aggiorna l'oggetto chiamando session.saveOrUpdate(object)o session.update(object)prima di chiamare evict ().


11

Ciò può accadere quando hai utilizzato lo stesso oggetto sessione per la lettura e la scrittura. Come? Supponi di aver creato una sessione. Hai letto un record dalla tabella dei dipendenti con la chiave primaria Emp_id = 101 Ora hai modificato il record in Java. E salverai il record dei dipendenti nel database. non abbiamo chiuso la sessione da nessuna parte qui. Poiché l'oggetto che è stato letto, persiste anche nella sessione. È in conflitto con l'oggetto che desideriamo scrivere. Da qui arriva questo errore.


9

Come qualcuno ha già indicato sopra, mi sono imbattuto in questo problema quando avevo cascade=allentrambe le estremità di una one-to-manyrelazione, quindi supponiamo che A -> B (uno-a-molti da A e molti-a-uno da B) e stia aggiornando l'istanza di B in A e quindi chiamando saveOrUpdate (A), si è verificata una richiesta di salvataggio circolare, ovvero il salvataggio di A attiva il salvataggio di B che attiva il salvataggio di A ... e in terza istanza quando l'entità (di A) è stata tentata di essere aggiunto a sessionPersistenceContext è stata generata l'eccezione duplicateObject.
  Potrei risolverlo rimuovendo la cascata da un'estremità.


Risolto il mio problema insieme a stackoverflow.com/questions/4334970/…
Magno C

5

È possibile utilizzare session.merge(obj), se si esegue il salvataggio con sessioni diverse con lo stesso oggetto persistente identificatore.
Ha funzionato, ho avuto lo stesso problema prima.


4

Ho anche riscontrato questo problema e ho avuto difficoltà a trovare l'errore.

Il problema che ho avuto è stato il seguente:

L'oggetto è stato letto da un Dao con una diversa sessione di ibernazione.

Per evitare questa eccezione, rileggi semplicemente l'oggetto con il dao che salverà / aggiornerà l'oggetto in seguito.

così:

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();
    }

}

Spero che questo faccia risparmiare un sacco di tempo ad alcune persone!


4

Mi sono imbattuto in questo problema:

  1. Eliminazione di un oggetto (utilizzando HQL)
  2. Memorizzazione immediata di un nuovo oggetto con lo stesso ID

L'ho risolto scaricando i risultati dopo l'eliminazione e svuotando la cache prima di salvare il nuovo oggetto

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

4

Questo problema si verifica quando aggiorniamo lo stesso oggetto della sessione, che abbiamo utilizzato per recuperare l'oggetto dal database.

È possibile utilizzare il metodo di unione di ibernazione invece del metodo di aggiornamento.

es. Prima usa session.get () e poi puoi usare session.merge (object). Questo metodo non creerà alcun problema. Possiamo anche usare il metodo merge () per aggiornare l'oggetto nel database.


3

Ottieni l'oggetto all'interno della sessione, qui un esempio:

MyObject ob = null;
ob = (MyObject) session.get(MyObject.class, id);

3
Bel tentativo, ma l'oggetto "ob" viene restituito senza i dati aggiornati (considerando che è stato aggiornato tramite applicazione in runtime, tra il recupero degli oggetti dal database e il suo salvataggio).
Alex

2

Le tue mappature di ID sono corrette? Se il database è responsabile della creazione dell'ID tramite un identificatore, è necessario mappare il proprio oggetto utente a quello.


2

Ho riscontrato questo problema con l'eliminazione di un oggetto, né lo sfratto né la cancellazione hanno aiutato.

/**
 * 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);
}

2

prima della posizione in cui iniziano gli oggetti ripetitivi, dovresti chiudere la sessione e quindi dovresti iniziare una nuova sessione

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

quindi in questo modo in una sessione non c'è più di un'entità che ha lo stesso identificatore.


2

In ritardo alla festa, ma può aiutare per i prossimi utenti -

Ho riscontrato questo problema quando seleziono un record utilizzando getsession() e aggiorno nuovamente un altro record con lo stesso identificatore utilizzando la stessa sessione causa il problema. Aggiunto codice di seguito.

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

Questo non dovrebbe mai essere fatto. La soluzione è eliminare la sessione prima dell'aggiornamento o modificare la logica di business.


1

Controlla se hai dimenticato di inserire @GenerateValue per la colonna @Id. Ho avuto lo stesso problema con molti a molti rapporti tra film e genere. Il programma ha lanciato l'errore Hibernate: org.hibernate.NonUniqueObjectException: un oggetto diverso con lo stesso valore identificativo era già associato all'errore di sessione. Ho scoperto in seguito che devo solo assicurarmi di avere @GenerateValue per il metodo get GenreId.


come posso applicare la tua soluzione alla mia domanda? creo una colonna id nella classe Task? stackoverflow.com/questions/55732955/...
sbattou

1

controlla semplicemente l'id se prende null o 0 come

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

in aggiunta o aggiornamento dove il contenuto è impostato dal modulo a Pojo


1

Sono nuovo in NHibernate e il mio problema era che ho usato una sessione diversa per interrogare il mio oggetto rispetto a quella che ho fatto per salvarlo. Quindi la sessione di salvataggio non sapeva dell'oggetto.

Sembra ovvio, ma leggendo le risposte precedenti cercavo dappertutto 2 oggetti, non 2 sessioni.


1

@GeneratedValue (strategy = GenerationType.IDENTITY), l'aggiunta di questa annotazione alla proprietà della chiave primaria nel tuo entity bean dovrebbe risolvere questo problema.


1

Ho risolto questo problema.
In realtà questo sta accadendo perché abbiamo dimenticato l'implementazione della proprietà PK Generator Type nella classe bean. Quindi rendilo di qualsiasi tipo come

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

quando persistiamo gli oggetti del bean, ogni oggetto acquisisce lo stesso ID, quindi il primo oggetto viene salvato, quando un altro oggetto da persistere allora HIB FW attraverso questo tipo di Exception: org.hibernate.NonUniqueObjectException:un oggetto diverso con lo stesso valore identificativo era già associato alla sessione.


1

Il problema si verifica perché nella stessa sessione di ibernazione stai tentando di salvare due oggetti con lo stesso identificatore. Ci sono due soluzioni: -

  1. Ciò sta accadendo perché non hai configurato correttamente il tuo file mapping.xml per i campi id come di seguito: -

    <id name="id">
      <column name="id" sql-type="bigint" not-null="true"/>
      <generator class="hibernateGeneratorClass"</generator>
    </id>
  2. Sovraccare il metodo getsession per accettare un parametro come isSessionClear e cancellare la sessione prima di restituire la sessione corrente come di seguito

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

Ciò causerà la cancellazione degli oggetti di sessione esistenti e anche se l'ibernazione non genera un identificatore univoco, supponendo che tu abbia configurato correttamente il tuo database per una chiave primaria usando qualcosa come Auto_Increment, dovrebbe funzionare per te.


1

Ho avuto un problema simile. Nel mio caso mi ero dimenticato di impostare il increment_byvalore nel database in modo che fosse lo stesso di quello usato da cache_sizee allocationSize. (Le frecce indicano gli attributi menzionati)

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

Giava:

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

1

Diversamente da quanto detto da wbdarby , può anche accadere quando un oggetto viene recuperato fornendo l'identificatore dell'oggetto a un HQL. In caso di tentativo di modificare i campi dell'oggetto e salvarlo nuovamente nel DB (la modifica potrebbe essere inserita, cancellata o aggiornata) nella stessa sessione , verrà visualizzato questo errore. Prova a cancellare la sessione di ibernazione prima di salvare l'oggetto modificato o crea una nuova sessione.

Spero di aver aiutato ;-)


1

Ho lo stesso errore che stavo sostituendo il mio set con uno nuovo ricevuto da Jackson.

Per risolvere questo problema mantengo il set esistente, rimuovo dal vecchio set l'elemento sconosciuto nel nuovo elenco con retainAll. Quindi aggiungo quelli nuovi con addAll.

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

Non c'è bisogno di avere la sessione e manipolarla.


1

Prova questo. Il sotto ha funzionato per me!

Nel hbm.xmlfile

  1. Dobbiamo impostare l' dynamic-updateattributo del tag di classe su true:

    <class dynamic-update="true">
  2. Imposta l'attributo di classe del tag del generatore nella colonna univoca su identity:

    <generator class="identity">

Nota: imposta la colonna univoca su identityanziché su assigned.


0

Un'altra cosa che ha funzionato per me è stata rendere la variabile di istanza Long al posto di long


Ho avuto la mia variabile di chiave primaria lungo id; cambiandolo in Long id; lavorato

Ti auguro il meglio


0

Puoi sempre fare un flush di sessione. Flush sincronizzerà lo stato di tutti i tuoi oggetti nella sessione (per favore, qualcuno mi corregga se sbaglio), e forse in alcuni casi risolverebbe il tuo problema.

L'implementazione dei tuoi uguali e hashcode può aiutare anche te.


0

Puoi controllare le tue Impostazioni Cascade. Le impostazioni Cascade sui tuoi modelli potrebbero causare questo. Ho rimosso le impostazioni Cascade (essenzialmente non consentendo inserimenti / aggiornamenti Cascade) e questo ha risolto il mio problema


0

Ho trovato anche questo errore. Quello che ha funzionato per me è assicurarmi che la chiave primaria (che viene generata automaticamente) non sia un PDT (cioè long, int, ect.), Ma un oggetto (cioè Long, Integer, ecc.)

Quando crei il tuo oggetto per salvarlo, assicurati di passare null e non 0.


0

questo aiuta?

User userObj1 = new User();
User userObj2 = userObj1;
.
.
.
rtsession.save(userObj1);
rtsession.save(userObj2); 

0

Ho risolto un problema simile come questo:

plan = (FcsRequestPlan) session.load(plan.getClass(), plan.getUUID());
while (plan instanceof HibernateProxy)
    plan = (FcsRequestPlan) ((HibernateProxy) plan).getHibernateLazyInitializer().getImplementation();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.