web-dev-qa-db-fra.com

Erreur Hibernate: org.hibernate.NonUniqueObjectException: un objet différent avec le même identifiant a déjà été associé à la session.

J'ai deux objets utilisateur et pendant que j'essaie de sauvegarder l'objet à l'aide de 

session.save(userObj);

Je reçois l'erreur suivante:

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]

Je crée la session en utilisant 

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

J'ai aussi essayé de faire la session.clear() avant de sauvegarder, toujours pas de chance.

C’est pour la première fois que je reçois l’objet de session quand une requête de l’utilisateur arrive, alors je comprends pourquoi dit que cet objet est présent dans la session.

Aucune suggestion?

97
harshit

J'ai eu cette erreur à plusieurs reprises et il peut être assez difficile à localiser ...

En gros, hibernate dit que vous avez deux objets qui ont le même identifiant (même clé primaire) mais ne sont pas le même objet.

Je vous suggère de décomposer votre code, c'est-à-dire de commenter les bits jusqu'à ce que l'erreur disparaisse, puis de remettre le code en place jusqu'à ce qu'il revienne et vous devriez trouver l'erreur.

Cela se produit le plus souvent via des sauvegardes en cascade où il existe une sauvegarde en cascade entre les objets A et B, mais l'objet B a déjà été associé à la session, mais pas sur la même instance de B.

Quel générateur de clé primaire utilisez-vous? 

La raison pour laquelle je pose cette question est que cette erreur est liée à la façon dont vous demandez à Hibernate de déterminer l’état persistant d’un objet (c’est-à-dire si un objet est persistant ou non). L'erreur peut se produire car hibernate tente de persister et un objet déjà persistant. En fait, si vous utilisez save, hibernate essaie de conserver cet objet, et peut-être existe-t-il déjà un objet avec la même clé primaire associée à la session.

Exemple

En supposant que vous ayez un objet de classe hibernation pour une table avec 10 lignes basées sur une combinaison de clés primaires (colonne 1 et colonne 2). Vous avez maintenant supprimé 5 lignes de la table à un moment donné. Maintenant, si vous essayez d'ajouter à nouveau les mêmes 10 lignes, alors qu'hibernate tente de conserver les objets dans la base de données, 5 lignes déjà supprimées seront ajoutées sans erreur. Maintenant, les 5 lignes restantes qui existent déjà lanceront cette exception. 

Donc, l’approche facile consisterait à vérifier si vous avez mis à jour/supprimé une valeur dans une table qui fait partie de quelque chose et plus tard, essayez-vous d’insérer à nouveau les mêmes objets

164
Michael Wiles

Ceci est seulement un point où hibernate crée plus de problèmes qu'il n'en résout . Dans mon cas, de nombreux objets portent le même identifiant 0, car ils sont nouveaux et n'en ont pas. La base de données les génère. Quelque part, j'ai lu que 0 signal n'identifie pas. La façon intuitive de les persister est de les parcourir et de les mettre en veille prolongée pour sauver les objets. Mais vous ne pouvez pas faire cela - "Bien sûr, vous devriez savoir que l'hibernation fonctionne ceci et ainsi, vous devez donc ..." works . En fin de compte, il est plus facile de le faire avec un simple mappeur vous-même, car l'hibernation n'est qu'un fardeau intransparent supplémentaire . faire presque tous les travaux manuellement. Mais si vous devez le faire quand même, utiliser le mode veille prolongée ne représente qu'un travail supplémentaire.

18
Hein

USe session.evict(object); La fonction de la méthode evict() permet de supprimer une instance du cache de session. Donc, pour la première fois, en enregistrant l'objet, enregistrez-le en appelant la méthode session.save(object) avant d'expulser l'objet du cache. De la même manière, mettez à jour l'objet en appelant session.saveOrUpdate(object) ou session.update(object) avant d'appeler evict ().

13
Rahul N

Cela peut se produire lorsque vous avez utilisé le même objet de session en lecture et en écriture. Comment? Supposons que vous ayez créé une session . Vous avez lu un enregistrement de la table employee avec la clé primaire Emp_id = 101 Vous avez maintenant modifié l'enregistrement en Java . Et vous allez enregistrer le Enregistrement d'employé dans la base de données ... Nous n'avons fermé la session nulle part ici ... puisque l'objet qui a été lu persiste également dans la session. Cela entre en conflit avec l'objet que nous souhaitons écrire. D'où cette erreur vient.

8
Prashant Bari

Comme quelqu'un l'a déjà indiqué ci-dessus, j'ai rencontré ce problème lorsque cascade=all se trouvait aux deux extrémités d'une relation one-to-many; supposons donc A -> B (un à plusieurs de A et plusieurs à un de B) et mettais à jour instance de B dans A puis appelant saveOrUpdate (A), il en résultait une demande de sauvegarde circulaire, c’est-à-dire que la sauvegarde de A déclenche la sauvegarde de B qui déclenche la sauvegarde de A ... et dans la troisième instance que l’entité (de A) était essayé d'être ajouté à la sessionPersistenceContext l'exception duplicateObject a été levée. 
Je pourrais le résoudre en supprimant la cascade d'un bout.

7
redzedi

J'ai aussi rencontré ce problème et j'ai eu du mal à trouver l'erreur.

Le problème que j'ai eu était le suivant:

L'objet a été lu par un Dao avec une session d'hibernation différente.

Pour éviter cette exception, relisez simplement l'objet avec le DAO qui va sauvegarder/mettre à jour cet objet ultérieurement.

alors:

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

}

J'espère que cela fera gagner du temps à certaines personnes!

4
Frithjof

J'ai rencontré ce problème en:

  1. Supprimer un objet (en utilisant HQL)
  2. Stocker immédiatement un nouvel objet avec le même identifiant

Je l'ai résolu en vidant les résultats après la suppression et en effaçant le cache avant d'enregistrer le nouvel objet.

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

Obtenez l'objet à l'intérieur de la session, voici un exemple:

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

J'ai rencontré ce problème avec la suppression d'un objet, ni l'expulsion ni clair aidé. 

/**
 * 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
TimP

J'ai la même erreur que je remplaçais mon Set par un nouveau get de Jackson.

Pour résoudre ceci, je conserve l'ensemble existant, je supprime de l'ancien ensemble l'élément unknown dans la nouvelle liste avec retainAll. J'ajoute ensuite les nouveaux avec addAll.

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

Pas besoin d'avoir la session et de la manipuler.

1
Ôrel

Le problème se produit parce que, dans la même session d'hibernation, vous essayez de sauvegarder deux objets avec le même identifiant. Il existe deux solutions: -

  1. Cela se produit car vous n'avez pas configuré correctement votre fichier mapping.xml pour les champs d'ID, comme ci-dessous: -

    <id name="id">
      <column name="id" sql-type="bigint" not-null="true"/>
      <generator class="hibernateGeneratorClass"</generator>
    </id>
    
  2. Surchargez la méthode getsession pour accepter un paramètre tel que isSessionClear, Et effacez la session avant de renvoyer la session en cours, comme ci-dessous.

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

Cela entraînera l'effacement des objets de session existants et même si hibernate ne génère pas d'identificateur unique, si vous avez correctement configuré votre base de données pour une clé primaire à l'aide de quelque chose comme Auto_Increment, cela devrait fonctionner pour vous.

1
Rahul Kumar

il suffit de vérifier l'identifiant si cela prend nul ou 0 comme

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

dans ajouter ou mettre à jour où le contenu est défini du formulaire à Pojo

1
Ayan Sarkar

@GeneratedValue (strategy = GenerationType.IDENTITY), l'ajout de cette annotation à la propriété de clé primaire de votre bean entity devrait résoudre ce problème.

1
Jay

Ce problème se produit lorsque nous mettons à jour le même objet de session, que nous avons utilisé pour extraire l'objet de la base de données.

Vous pouvez utiliser la méthode de fusion de hibernation au lieu de la méthode de mise à jour.

par exemple. Commencez par utiliser session.get (), puis par session.merge (objet). Cette méthode ne créera aucun problème. Nous pouvons également utiliser la méthode merge () pour mettre à jour un objet dans la base de données.

1

Autrement que ce quewbdarbya dit, cela peut même arriver quand un objet est récupéré en donnant l'identifiant de l'objet à un HQL. Si vous essayez de modifier les champs d’objet et de les sauvegarder dans la base de données (les modifications peuvent être insérées, supprimées ou mises à jour) au cours de la même session , cette erreur apparaîtra. Essayez de vider la session d'hibernation avant d'enregistrer votre objet modifié ou de créer une nouvelle session .

J'espère que j'ai aidé ;-)

1
Arash moradabadi

Essaye ça. Le dessous a fonctionné pour moi!

Dans le fichier hbm.xml

  1. Nous devons définir l'attribut dynamic-update de la balise de classe sur true:

    <class dynamic-update="true">
    
  2. Définissez l'attribut de classe de la balise générateur dans la colonne unique sur identity:

    <generator class="identity">
    

Remarque: définissez la colonne unique sur identity plutôt que assigned.

1
Explorer_N

Vérifiez si vous avez oublié de mettre @GenerateValue pour la colonne @Id .J'ai eu le même problème avec plusieurs à plusieurs relations entre Film et Genre. Le programme a lancé Erreur Hibernate: org.hibernate.NonUniqueObjectException: un objet différent avec la même valeur d'identifiant était déjà associé à la session Erreur . J'ai découvert plus tard que je devais simplement m'assurer que vous aviez @GenerateValue à la méthode GenreId get.

1
Thupten

NHibernate est un nouvel utilisateur. Le problème, c’est que j’ai utilisé une session différente pour interroger mon objet et pour l’enregistrer. Donc, la session de sauvegarde ne connaissait pas l'objet. 

Cela semble évident, mais en lisant les réponses précédentes, je cherchais partout 2 objets, pas 2 sessions.

1
DustinA

Les correspondances de vos identifiants sont-elles correctes? Si la base de données est responsable de la création de l'identifiant via un identifiant, vous devez mapper votre objet utilisateur sur cet identifiant.

1
cwap

avant de commencer à positionner les objets répétitifs, vous devez fermer la session .__ et commencer une nouvelle session

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

ainsi, de la sorte, dans une session, il n’existe pas plus d’une entité ayant le même identifiant.

1
engtuncay

J'avais un problème similaire. Dans mon cas, j'avais oublié de définir la valeur increment_by dans la base de données de la même façon que celle utilisée par cache_size et allocationSize. (Les flèches indiquent les attributs mentionnés)

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 <-)
1
kaba713

Vous pouvez utiliser session.merge(obj), si vous effectuez une sauvegarde avec différentes sessions avec le même identifiant d'objet persistant.
Cela a fonctionné, j'avais même problème avant.

1
Pavan Kumar

Vous pouvez vérifier vos paramètres de cascade. Cela pourrait être causé par les paramètres Cascade de vos modèles. J'ai supprimé les paramètres Cascade (n'autorisant pas les insertions/mises à jour Cascade) et cela a résolu mon problème.

0
user1609848

Vous pouvez toujours faire une session flush . Flush synchronisera l'état de tous vos objets en session (s'il vous plaît, corrigez-moi si je me trompe), et cela résoudrait peut-être votre problème dans certains cas.

Implémenter vos propres égaux et hashcode peut également vous aider.

0
caarlos0

J'ai résolu un problème similaire comme celui-ci:

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

Est-ce que cela aide? 

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

Une autre chose qui a fonctionné pour moi a été de rendre la variable d'instance Long au lieu de long


J'ai eu ma variable principale primaire long id; Le changer en Long id; travaillé

Bonne chance

0
Ashishakgupta

J'ai résolu ce problème. 
En fait, cela se produit car nous avons oublié l'implémentation de la propriété Generator Type of PK dans la classe de haricot. Alors faites-en n'importe quel type comme 

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

quand nous persistons les objets de bean, chaque objet a acquis le même ID, donc le premier objet est enregistré, lorsqu'un autre objet persiste, puis HIB FW via ce type de Exception: org.hibernate.NonUniqueObjectException:, un objet différent avec le même identifiant a déjà été associé à la session.

0
Ankit Sharma

En retard à la fête, mais peut aider pour les utilisateurs à venir - 

J'ai eu ce problème lorsque je sélectionnez un enregistrement en utilisant getsession() et encore update un autre enregistrement avec le même identifiant en utilisant même session provoque le problème. Code ajouté ci-dessous.

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

Cela ne devrait jamais être fait. La solution consiste à expulser la session avant la mise à jour ou à modifier la logique métier.

0
vipin cp

Une solution de contournement pour résoudre ce problème consiste à essayer de relire l'objet à partir de hibernate cache/db avant d'effectuer toute mise à jour, puis de persister.

Exemple:

            OrderHeader oh = orderHeaderDAO.get(orderHeaderId);
            oh.setShipFrom(facilityForOrder);
            orderHeaderDAO.persist(oh);

Remarque: Gardez à l'esprit que cela ne résout pas la cause première mais résout le problème.

0
Nuwan

J'ai trouvé cette erreur aussi. Ce qui a fonctionné pour moi est de m'assurer que la clé primaire (générée automatiquement) n'est pas un PDT (c'est-à-dire long, int, ect.), Mais un objet (c'est-à-dire long, Integer, etc.)

Lorsque vous créez votre objet pour le sauvegarder, assurez-vous de passer null et non 0.

0
Jaco Van Niekerk