Question

EntityManager.merge() peut insérer de nouveaux objets et mettre à jour ceux qui existent déjà.

Pourquoi voudrait-on utiliser persist() (qui ne peut créer de nouveaux objets)?

Était-ce utile?

La solution

De toute façon ajoutera une entité à une PersistenceContext, la différence est dans ce que vous faites avec l'entité après.

Persistent prend une instance d'entité, il ajoute au contexte et fait cette instance géré (par exemple les futures mises à jour de l'entité seront suivis).

Fusionner crée une nouvelle instance de votre entité, copie l'état de l'entité fournie, et fait géré la nouvelle copie. L'instance que vous passez ne sera pas géré (toutes les modifications apportées ne feront pas partie de la transaction - à moins que vous appelez à nouveau fusionner).

Peut-être un exemple de code vous aidera.

MyEntity e = new MyEntity();

// scenario 1
// tran starts
em.persist(e); 
e.setSomeField(someValue); 
// tran ends, and the row for someField is updated in the database

// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue); 
// tran ends but the row for someField is not updated in the database
// (you made the changes *after* merging)

// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue); 
// tran ends and the row for someField is updated
// (the changes were made to e2, not e)

Scénario 1 et 3 sont à peu près équivalents, mais il y a des situations où vous voudriez utiliser le scénario 2.

Autres conseils

persisteront et de fusion sont à deux fins différentes (ils ne sont pas des solutions de rechange à tous).

(sous la direction d'étendre des informations sur les différences)

persistent:

  • Insérez un nouveau registre à la base de données
  • Joindre l'objet au responsable de l'entité.

fusion:

  • Trouver un objet attaché avec le même identifiant et le mettre à jour.
  • Si existe mise à jour et de retourner l'objet déjà attaché.
  • Si n'existe pas insérer le nouveau registre à la base de données.

efficacité persistent ():

  • Il pourrait être plus efficace pour l'insertion d'un nouveau registre à une base de données de fusion ().
  • Il ne reproduit pas l'objet original.

persister () sémantique:

  • Il veille à ce que vous insérez et non la mise à jour par erreur.

Exemple:

{
    AnyEntity newEntity;
    AnyEntity nonAttachedEntity;
    AnyEntity attachedEntity;

    // Create a new entity and persist it        
    newEntity = new AnyEntity();
    em.persist(newEntity);

    // Save 1 to the database at next flush
    newEntity.setValue(1);

    // Create a new entity with the same Id than the persisted one.
    AnyEntity nonAttachedEntity = new AnyEntity();
    nonAttachedEntity.setId(newEntity.getId());

    // Save 2 to the database at next flush instead of 1!!!
    nonAttachedEntity.setValue(2);
    attachedEntity = em.merge(nonAttachedEntity);

    // This condition returns true
    // merge has found the already attached object (newEntity) and returns it.
    if(attachedEntity==newEntity) {
            System.out.print("They are the same object!");
    }

    // Set 3 to value
    attachedEntity.setValue(3);
    // Really, now both are the same object. Prints 3
    System.out.println(newEntity.getValue());

    // Modify the un attached object has no effect to the entity manager
    // nor to the other objects
    nonAttachedEntity.setValue(42);
}

De cette façon, existe seulement 1 objet attaché à un registre dans le gestionnaire de l'entité.

fusion () pour une entité avec un id est quelque chose comme:

AnyEntity myMerge(AnyEntity entityToSave) {
    AnyEntity attached = em.find(AnyEntity.class, entityToSave.getId());
    if(attached==null) {
            attached = new AnyEntity();
            em.persist(attached);
    }
    BeanUtils.copyProperties(attached, entityToSave);

    return attached;
}

Bien que s'il est connecté à MySQL merge () pourrait être aussi efficace que persist () à l'aide d'un appel à RESPECTEZ Duplicate option KEY UPDATE, JPA est une programmation de très haut niveau et vous ne pouvez pas supposer que cela va être le cas partout.

Si vous utilisez le générateur assigned, en utilisant la fusion au lieu de persister peut provoquer une SQL redondante déclaration , ce qui affecte les performances.

En outre, appeler fusion des entités gérées est également une erreur puisque les entités gérées sont automatiquement géré par Hibernate et leur état est synchronisé avec l'enregistrement de base de données par le mécanisme de vérification sale sur chasse le contexte de persistance .

Pour comprendre comment tout cela fonctionne, vous devez d'abord savoir que Hibernate décale l'état d'esprit des développeurs des états SQL transitions d'état d'entité .

Une fois qu'une entité est gérée de manière active par Hibernate, tous les changements vont se propager automatiquement à la base de données.

Hibernate surveille actuellement les entités ci-joints. Mais pour une entité aménagée, elle doit être dans l'état d'entité droit.

Tout d'abord, il faut définir tous les états d'entité:

  • Nouveau (transitoire)

    Un objet nouvellement créé qui n'a pas jamais été associé à une mise en veille prolongée Session (a.k.a Persistence Context) et ne sont pas mis en correspondance avec une ligne de table de base de données est considérée comme dans l'état de New (transitoire).

    Pour devenir persévéré, nous devons soit appeler explicitement la méthode ou utiliser EntityManager#persist du mécanisme de persistance transitive.

  • persistante (géré)

    Une entité persistante a été associée à une ligne de la table de base de données et il est géré par le contexte de persistance en cours d'exécution en cours. Toute modification apportée à cette entité va être détectée et propagée à la base de données (au cours de la session à temps de rinçage). Avec Hibernate, nous n'avons plus d'exécuter des instructions INSERT / UPDATE / DELETE. Mise en veille prolongée utilise un le style d'écriture-behind travail transactionnel et les changements sont synchronisé au dernier moment responsable, pendant la durée d'injection de courant <=>.

  • individuelle

    Une fois le contexte de persistance en cours d'exécution en cours est fermé toutes les entités gérées auparavant se détachent. Les changements successifs ne seront plus suivis et aucune synchronisation de base de données automatique va se passer.

    Pour associer une entité détachée à une session active Hibernate, vous pouvez choisir l'une des options suivantes:

    • refixer

      Mise en veille prolongée (mais pas JPA 2.1) soutient refixer par la session méthode de mise à jour #. Une session Hibernate ne peut associer un objet entité pour une ligne de base de données. En effet, la persistance Contexte agit comme un cache en mémoire (antémémoire de premier niveau) et une seule valeur (entité) est associée à une clé donnée (type d'entité et de l'identificateur de base de données). Une entité peut être remis en place que s'il n'y a pas d'autre objet de la JVM (correspondant à la même ligne de base de données) déjà associée à la session en cours mise en veille prolongée.

    • Fusion

    La fusion va copier l'état d'entité détachée (source) à une instance d'entité gérée (destination). Si l'entité de fusion n'a pas d'équivalent dans la session en cours, on sera extraite de la base de données. L'instance d'objet détaché continuera à rester détaché même après l'opération de fusion.

  • Retiré

    Bien que les demandes JPA qui géraient les entités ne sont autorisés à supprimer, Hibernate peut également supprimer des entités indépendantes (mais seulement par une session # Supprimer appel de méthode). Une entité supprimée est uniquement prévue pour la suppression et la base de données réelle DELETE sera exécuterd lors de la Session-temps de rinçage.

Pour comprendre les transitions d'état JPA mieux, vous pouvez visualiser le schéma suivant:

entrer image description ici

Ou si vous utilisez l'API spécifique Hibernate:

entrer image description ici

J'ai remarqué que quand je em.merge, je suis une déclaration pour chaque SELECT INSERT, même quand il n'y avait pas de champ que JPA générait pour moi - la clé primaire était un UUID que je mets moi même. Je suis passé à seulement reçu et em.persist(myEntityObject) déclarations alors <=>.

La spécification JPA dit ce qui suit à propos de persist().

  

Si X est un objet détaché, peut être le EntityExistsException Renvoyé lorsque le persistent   opération est invoquée, ou l'autre ou PersistenceException peut être jeté @GeneratedValue à chasse d'eau ou consacrer du temps.

Donc, en utilisant @Id Conviendrait lorsque l'objet ne doit pas pour être un objet détaché. Vous préférez peut-être avoir le code jeter le merge() il échoue rapidement.

Bien que la spécification est manque de clarté, <=> pourrait définir le <=> pour un objet <=>. Doivent cependant avoir <=> un objet avec le déjà généré <=>.

Il y a quelques différences entre les plus et merge persist (j'énumérer à nouveau ceux déjà posté ici):

D1. Ne fait pas IllegalArgumentException l'entité gérée passé, mais renvoie plutôt une autre instance qui est géré. De l'autre SELECT côté fera l'entité passée gérée:

//MERGE: passedEntity remains unmanaged, but newEntity will be managed
Entity newEntity = em.merge(passedEntity);

//PERSIST: passedEntity will be managed after this
em.persist(passedEntity);

D2. Si vous supprimez une entité, puis décidez de conserver l'entité en arrière, vous pouvez le faire qu'avec persist (), parce que lèveront une <=> <=>.

D3. Si vous avez décidé de prendre en charge manuellement vos identifiants (par exemple en utilisant UUID), puis un <=> opération déclenche les requêtes ultérieures afin de <=> rechercher des entités existantes avec cet ID, alors que ne peut pas avoir besoin <=> ces requêtes.

D4. Il y a des cas où vous ne faites pas confiance tout simplement le code qui appelle votre code, et afin de vous assurer qu'aucune donnée ne soit mis à jour, mais est inséré, vous devez utiliser <=>.

Quelques détails sur la fusion et qui vous aideront à utiliser la fusion sur persistent:

  

De retour d'une instance gérée autre que l'entité d'origine est un élément essentiel de la fusion   processus. Si une instance d'entité avec le même identifiant existe déjà dans le contexte de la persistance, la   fournisseur remplacera son état à l'état de l'entité qui est en cours de fusion, mais la gestion   version qui existait doit déjà être renvoyé au client afin qu'il puisse être utilisé. Si le fournisseur n'a pas   mettre à jour l'instance des employés dans le contexte de persistance, toute référence à cette instance deviendront   incompatible avec le nouvel état fusionné dans.

     

Lorsque la fusion () est appelée sur une nouvelle entité, il se comporte de façon similaire à l'opération persist (). il ajoute   l'entité au contexte de persistance, mais au lieu d'ajouter l'instance d'entité d'origine, il crée une nouvelle   copier et gère cette instance à la place. La copie qui est créée par l'opération de fusion () est conservée   comme si l'on a invoqué la méthode persist () sur elle.

     

En présence de relations, l'opération de fusion () tentera de mettre à jour l'entité gérée   pour pointer vers les versions gérées des entités référencées par l'entité détachée. Si l'entité a une   rapport à un objet qui n'a pas d'identité persistante, le résultat de l'opération de fusion est   indéfini. Certains fournisseurs pourraient permettre à la copie a réussi à pointer vers l'objet non persistant,   tandis que d'autres pourraient jeter une exception immédiatement. L'opération de fusion () peut être éventuellement   dans ces cas en cascade pour éviter une exception de se produire. Nous couvrirons en cascade de la fusion ()   fonctionnement plus loin dans cette section. Si une entité fusionnée des points à une entité supprimée, une   IllegalArgumentException exception sera levée.

     

relations Lazy-chargement sont un cas particulier dans l'opération de fusion. Si un chargement paresseux   relation n'a pas été déclenchée sur une entité avant qu'elle ne se détache, cette relation sera   ignoré lorsque l'entité est fusionnée. Si la relation a été déclenchée alors géré et mis à zéro alors que l'entité a été détachée, la version gérée de l'entité aura également la relation effacée lors de la fusion. "

Toutes les informations ci-dessus a été prise de "Pro JPA 2 Maîtriser l'API Java ™ persistance" par Mike Keith et Merrick Schnicariol. Chapitre 6. détachement de la section et de la fusion. Ce livre est en fait un deuxième livre consacré à JPA par les auteurs. Ce nouveau livre a beaucoup de nouvelles informations puis ancienne. Je recommande vraiment lire ce livre pour ceux qui seront sérieusement impliqués avec JPA. Je suis désolé pour l'affichage de ma première réponse anonymement.

Je recevais des exceptions lazyLoading sur mon entité parce que j'essaie d'accéder à une collection chargée paresseuse qui était en session.

Ce que je fais est dans une demande séparée, permet de récupérer l'entité de session et essaie ensuite d'accéder à une collection dans ma page jsp qui était problématique.

Pour remédier à cela, je mis à jour la même entité dans mon contrôleur et passé à mon jsp, bien que je pense quand je réenregistrés en session qu'il sera également accessible si et ne pas jeter SessionScope un LazyLoadingException, une modification de l'exemple 2:

Ce qui suit a travaillé pour moi:

// scenario 2 MY WAY
// tran starts
e = new MyEntity();
e = em.merge(e); // re-assign to the same entity "e"

//access e from jsp and it will work dandy!!

En passant par les réponses il y a quelques détails manquants concernant `Cascade » et la génération id. Voir la question

En outre, il convient de mentionner que vous pouvez avoir séparés des annotations pour la fusion Cascade et persistant. Et Cascade.MERGE qui seront Cascade.PERSIST traités selon la méthode utilisée

La spécification est votre ami;)

Je trouve cette explication de la documentation Hibernate éclairantes, car ils contiennent un cas d'utilisation:

  

L'utilisation et la sémantique de fusion () semble être source de confusion pour les nouveaux utilisateurs. Tout d'abord, aussi longtemps que vous n'êtes pas essayez d'utiliser l'état d'objet chargé dans un gestionnaire d'entités dans un nouveau gestionnaire d'entités, vous devez pas besoin d'utiliser la fusion () tout . Certaines applications n'utiliseront jamais cette méthode.

     

Habituellement, la fusion () est utilisé dans le scénario suivant:

     
      
  • L'application charge un objet dans le premier gestionnaire d'entités
  •   
  • l'objet est passé à la couche de présentation
  •   
  • quelques modifications sont apportées à l'objet
  •   
  • l'objet est passé vers le bas à la couche logique métier
  •   
  • l'application persiste ces modifications en appelant la fusion () dans un second gestionnaire d'entités
  •   
     

Voici la sémantique exacte de fusion ():

     
      
  • s'il y a une instance gérée avec le même identifiant actuellement associé au contexte de persistance, copier l'état de l'objet donné dans l'instance géré
  •   
  • s'il n'y a pas d'instance gérée actuellement associée au contexte de persistance, essayez de le charger à partir de la base de données, ou créer une nouvelle instance gérée
  •   
  • l'instance gérée est retourné
  •   
  • l'instance donnée ne devient pas associée au contexte de persistance, il reste détaché et est habituellement mis au rebut
  •   

De: http: //docs.jboss. org / hiberner / entitymanager / 3,6 / référence / fr / html / objectstate.html

  

JPA est incontestablement une grande simplification dans le domaine de l'entreprise   applications construites sur la plate-forme Java. En tant que développeur qui a dû   faire face à la complexité des anciens beans entités dans J2EE je vois la   inclusion de JPA parmi les spécifications Java EE comme un grand saut   vers l'avant. Cependant, tout en approfondissant les détails JPA je trouve   des choses qui ne sont pas si facile. Dans cet article, je traite la comparaison des   la fusion de EntityManager et persisteront méthodes dont chevauchement   comportement peut provoquer la confusion non seulement à un débutant. De plus, je   proposer une généralisation qui voit les deux méthodes comme des cas particuliers d'un   méthode plus générale moissonneuse-batteuse.

entités Persistance

Contrairement à la méthode de fusion de la méthode est assez obstinent simple et intuitive. Le scénario le plus courant de l'utilisation de la méthode persistent peut se résumer comme suit:

"Une instance nouvellement créée de la classe d'entité est passée à la méthode persistera. Après cette méthode retourne, l'entité est gérée et planifiée pour l'insertion dans la base de données. Il peut arriver avant ou la transaction est validée ou lorsque la méthode de chasse est appelée. Si l'entité fait référence à une autre entité par le biais d'une relation marquée avec la stratégie en cascade PERSISTERONT cette procédure est appliquée également. "

 ici

La spécification va plus dans les détails, cependant, leur souvenir n'est pas essentiel que ces détails portent sur des situations plus ou moins exotiques seulement.

Fusion des entités

Par rapport à persister, la description du comportement de la fusion est pas si simple. Il n'y a pas de scénario principal, comme dans le cas de persister, et un programmeur doit se rappeler tous les scénarios afin d'écrire un code correct. Il me semble que les concepteurs JPA voulait avoir une méthode dont la principale préoccupation serait la manipulation des entités individuelles (comme l'opposé de la méthode persisteront qui traite des entités nouvellement créées principalement.) Tâche principale de la méthode de fusion est de transférer l'état d'un entité non géré (en argument) à son homologue géré dans le contexte de persistance. Cette tâche, cependant, divise encore en plusieurs scénarios qui aggravent l'intelligibilité du comportement de la méthode globale.

Au lieu de répéter les paragraphes de la JPA j'ai préparé un organigramme qui représente schématiquement le comportement de la méthode de fusion:

 ici

Alors, quand dois-je utiliser persist et quand fusion?

persistent

  • Vous voulez que la méthode crée toujours une nouvelle entité et met à jour jamais une entité. Dans le cas contraire, la méthode renvoie une exception en raison de la violation de l'unicité de clé primaire.
  • processus batch, la manipulation des entités de manière stateful (voir modèle de passerelle).
  • Optimisation des performances

fusion

  • Vous voulez que la méthode soit inserts ou met à jour une entité dans la base de données.
  • Vous voulez gérer les entités d'une manière sans état (objets transfert de données dans les services)
  • Vous souhaitez insérer une nouvelle entité qui peut avoir une référence à une autre entité qui peut, mais ne peut pas être encore créé (relation doit être marquée Merge). Par exemple, l'insertion d'une nouvelle photo avec une référence à une nouvelle ou un album pré-existante.

Scénario X:

Tableau: Spitter (One), Tableau: Spittles (Many) (Spittles est propriétaire de la relation avec un FK: spitter_id)

Ce scénario se traduit par des économies: Le Spitter et les deux Spittles comme propriété de même Spitter

.
        Spitter spitter=new Spitter();  
    Spittle spittle3=new Spittle();     
    spitter.setUsername("George");
    spitter.setPassword("test1234");
    spittle3.setSpittle("I love java 2");       
    spittle3.setSpitter(spitter);               
    dao.addSpittle(spittle3); // <--persist     
    Spittle spittle=new Spittle();
    spittle.setSpittle("I love java");
    spittle.setSpitter(spitter);        
    dao.saveSpittle(spittle); //<-- merge!!

Scénario Y:

Cela permettra d'économiser le Spitter, sauvera les 2 Spittles Mais ils ne seront pas référence à la même Spitter!

        Spitter spitter=new Spitter();  
    Spittle spittle3=new Spittle();     
    spitter.setUsername("George");
    spitter.setPassword("test1234");
    spittle3.setSpittle("I love java 2");       
    spittle3.setSpitter(spitter);               
    dao.save(spittle3); // <--merge!!       
    Spittle spittle=new Spittle();
    spittle.setSpittle("I love java");
    spittle.setSpitter(spitter);        
    dao.saveSpittle(spittle); //<-- merge!!

Une autre observation:

merge() va ne se soucient que d'un identifiant généré automatiquement (testé sur et IDENTITY SEQUENCE) lorsqu'un enregistrement avec un tel id existe déjà dans votre table. Dans ce cas, va essayer de persist() mettre à jour le dossier. Si, cependant, un identifiant est absent ou ne correspond pas à tous les enregistrements existants, ignoreront complètement <=> et demander un db d'allouer un nouveau. Cela est parfois une source d'un grand nombre de bugs. Ne pas utiliser pour forcer un <=> id pour un nouveau record.

<=> d'autre part ne vous laissera jamais passer même une carte d'identité à elle. Il échouera immédiatement. Dans mon cas, il est:

  

causés par: org.hibernate.PersistentObjectException: entité individuelle   transmis à persister

mise en veille prolongée JPA javadoc a un indice:

  

Lancers : javax.persistence.EntityExistsException - si l'entité   existe déjà. (Si l'entité existe déjà, la   EntityExistsException peut être levée lorsque l'opération est persistent   Invoqué, ou EntityExistsException ou d'une autre PersistenceException   peut être levée au moment de chasse ou de commettre.)

Vous avez peut-être venir ici pour obtenir des conseils sur quand utiliser persistent et quand utiliser fusionner . Je pense que cela dépend de la situation. Comment est-il probable que vous devez créer un nouvel enregistrement et comment est-il difficile de récupérer des données conservées

Laissez-présumons vous pouvez utiliser une clé naturelle / identifiant.

  • Les données doivent être persisté, mais de temps en temps un enregistrement existe et une mise à jour est nécessaire. Dans ce cas, vous pouvez essayer un persister et si elle jette un EntityExistsException, vous le chercher et de combiner les données:

    try {entityManager.persist (entité)}

    catch (exception EntityExistsException) {/ * récupérer et fusionner * /}

  • Persisté données doivent être mises à jour, mais de temps en temps il n'y a pas d'enregistrement pour les données encore. Dans ce cas, vous regardez vers le haut, et faites persister si l'entité est manquante:

    entity = entityManager.find (clé);

    if (entité == NULL) {entityManager.persist (entité); }

    else {/ * fusion * /}

Si vous ne possédez pas la clé naturelle / identifiant, vous aurez plus de mal à comprendre si l'entité existe ou non, ou comment chercher.

Les fusions peuvent être traitées de deux façons aussi:

  1. Si les changements sont généralement de petite taille, les appliquer à l'entité gérée.
  2. Si les changements sont fréquents, copiez l'ID de l'entité persistait ainsi que des données non altérées. Ensuite, appelez EntityManager :: fusion () pour remplacer l'ancien contenu.

persistent (entité) doit être utilisé avec des entités totalement nouvelles, pour les ajouter à la DB (si l'entité existe déjà dans DB, il y aura EntityExistsException jet).

fusion (entité) doit être utilisée pour mettre au contexte entité retour de persistance si l'entité a été détaché et a été modifiée.

Probablement persist génère instruction SQL INSERT et fusion instruction SQL UPDATE (mais je ne suis pas sûr).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top