web-dev-qa-db-fra.com

Quelles sont les différences entre les différentes méthodes d’épargne dans Hibernate?

Hibernate a une poignée de méthodes qui, d’une manière ou d’une autre, prennent votre objet et le mettent dans la base de données. Quelles sont les différences entre elles, quand utiliser lesquelles et pourquoi n’existe-t-il pas une seule méthode intelligente qui sait quand utiliser quoi?

Les méthodes que j'ai identifiées jusqu'à présent sont:

  • save()
  • update()
  • saveOrUpdate()
  • saveOrUpdateCopy()
  • merge()
  • persist()
196
Henrik Paul

Voici ma compréhension des méthodes. Celles-ci sont principalement basées sur le API bien que, dans la pratique, je n’utilise pas tout cela.

saveOrUpdate Les appels sont sauvegardés ou mis à jour en fonction de certaines vérifications. Par exemple. si aucun identifiant n'existe, save est appelé. Sinon, update est appelé.

save persiste une entité. Attribuera un identifiant s'il n'en existe pas. Si on le fait, il fait essentiellement une mise à jour. Renvoie l'ID généré de l'entité.

update Tente de conserver l'entité à l'aide d'un identifiant existant. Si aucun identifiant n'existe, je crois qu'une exception est levée.

saveOrUpdateCopy Ceci est obsolète et ne devrait plus être utilisé. Au lieu de cela il y a ...

fusionner Voilà où mes connaissances commencent à faiblir. La chose importante ici est la différence entre les entités transitoires, détachées et persistantes. Pour plus d'informations sur les états d'objet, jetez un coup d'oeil ici . Avec Save & Update, vous traitez avec des objets persistants. Ils sont liés à une session afin que Hibernate sache ce qui a changé. Mais lorsque vous avez un objet transitoire, aucune session n'est impliquée. Dans ces cas-là, vous devez utiliser la fusion pour les mises à jour et continuer à enregistrer.

persist Comme mentionné ci-dessus, ceci est utilisé sur les objets transitoires. Il ne renvoie pas l'ID généré.

117
Lee Theobald
╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║    METHOD    ║            TRANSIENT          ║            DETACHED            ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║       sets id if doesn't      ║   sets new id even if object   ║
║    save()    ║     exist, persists to db,    ║    already has it, persists    ║
║              ║    returns attached object    ║ to DB, returns attached object ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║       sets id on object       ║             throws             ║
║   persist()  ║     persists object to DB     ║       PersistenceException     ║
║              ║                               ║                                ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║                               ║                                ║
║   update()   ║           Exception           ║     persists and reattaches    ║
║              ║                               ║                                ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║  copy the state of object in  ║    copy the state of obj in    ║
║    merge()   ║     DB, doesn't attach it,    ║      DB, doesn't attach it,    ║
║              ║    returns attached object    ║     returns attached object    ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║                               ║                                ║
║saveOrUpdate()║           as save()           ║            as update()         ║
║              ║                               ║                                ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
114
Sergii Shevchyk
  • Voir le Forum Hibernate pour une explication des différences subtiles entre persister et sauvegarder. La différence semble correspondre au moment où l'instruction INSERT est exécutée. Puisque save renvoie l'identifiant, l'instruction INSERT doit être exécutée instantanément, quel que soit l'état de la transaction (ce qui est généralement une mauvaise chose). Persister n'exécutera aucune instruction en dehors de la transaction en cours d'exécution uniquement pour attribuer l'identifiant. Enregistrer/Persister tous les deux sur instances transitoires, c’est-à-dire les instances auxquelles aucun identificateur n’a encore été attribué et qui, en tant que telles, ne sont pas enregistrées dans la base de données.

  • Mettre à jour et Fusionner les deux fonctionnent sur instances détachées, c’est-à-dire les instances ayant une entrée correspondante dans la base de données mais qui ne sont actuellement pas rattachées à (ou gérées par) une session. La différence entre eux est ce qui arrive à l'instance qui est transmise à la fonction. update tente de rattacher l'instance, ce qui signifie qu'il ne peut y avoir aucune autre instance de l'entité persistante attachée à la session pour le moment, sinon une exception est levée. merge , cependant, ne copie que toutes les valeurs dans une instance persistante de la session (qui sera chargée si elle n'est pas chargée). L'objet d'entrée n'est pas modifié. Ainsi, la fusion est plus générale que la mise à jour , mais peut utiliser davantage de ressources.

65
jrudolph

Ce lien explique de manière pertinente:

http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/

Nous avons tous les problèmes que nous rencontrons assez rarement, mais quand nous les reverrons, nous savons que nous avons résolu le problème, mais nous ne nous souvenons plus comment.

L'exception NonUniqueObjectException levée lors de l'utilisation de Session.saveOrUpdate () dans Hibernate est l'une des miennes. J'ajouterai de nouvelles fonctionnalités à une application complexe. Tous mes tests unitaires fonctionnent bien. Ensuite, en testant l'interface utilisateur et en essayant de sauvegarder un objet, je commence à recevoir une exception avec le message "un autre objet avec le même identifiant a déjà été associé à la session". Voici un exemple de code tiré de Java Persistence with Hibernate .

            Session session = sessionFactory1.openSession();
            Transaction tx = session.beginTransaction();
            Item item = (Item) session.get(Item.class, new Long(1234));
            tx.commit();
            session.close(); // end of first session, item is detached

            item.getId(); // The database identity is "1234"
            item.setDescription("my new description");
            Session session2 = sessionFactory.openSession();
            Transaction tx2 = session2.beginTransaction();
            Item item2 = (Item) session2.get(Item.class, new Long(1234));
            session2.update(item); // Throws NonUniqueObjectException
            tx2.commit();
            session2.close();

Pour comprendre la cause de cette exception, il est important de comprendre les objets détachés et ce qui se produit lorsque vous appelez saveOrUpdate () (ou simplement update ()) sur un objet détaché.

Lorsque nous fermons une session Hibernate individuelle, les objets persistants avec lesquels nous travaillons sont détachés. Cela signifie que les données sont toujours dans la mémoire de l’application, mais Hibernate n’est plus responsable du suivi des modifications apportées aux objets.

Si nous modifions ensuite notre objet détaché et voulons le mettre à jour, nous devons le rattacher. Au cours de ce processus de recollement, Hibernate vérifiera s'il existe d'autres copies du même objet. S'il en trouve, il doit nous dire qu'il ne sait plus ce qu'est la "vraie" copie. D'autres modifications ont peut-être été apportées aux autres copies que nous nous attendons à enregistrer, mais Hibernate ne les connaît pas, car elles ne les géraient pas à ce moment-là.

Plutôt que de sauvegarder des données éventuellement mauvaises, Hibernate nous informe du problème via l’Exception NonUniqueObjectException.

Alors, que devons-nous faire? Dans Hibernate 3, nous avons merge () (dans Hibernate 2, utilisez saveOrUpdateCopy ()). Cette méthode forcera Hibernate à copier toutes les modifications d'autres instances détachées sur celle que vous souhaitez enregistrer, et fusionnera donc toutes les modifications en mémoire avant la sauvegarde.

        Session session = sessionFactory1.openSession();
        Transaction tx = session.beginTransaction();
        Item item = (Item) session.get(Item.class, new Long(1234));
        tx.commit();
        session.close(); // end of first session, item is detached

        item.getId(); // The database identity is "1234"
        item.setDescription("my new description");
        Session session2 = sessionFactory.openSession();
        Transaction tx2 = session2.beginTransaction();
        Item item2 = (Item) session2.get(Item.class, new Long(1234));
        Item item3 = session2.merge(item); // Success!
        tx2.commit();
        session2.close();

Il est important de noter que la fusion renvoie une référence à la version mise à jour de l'instance. Il ne s'agit pas de rattacher un élément à la session. Si vous testez l’égalité d’instance (item == item3), vous constaterez qu’elle renvoie false dans ce cas. Vous voudrez probablement travailler avec item3 à partir de maintenant.

Il est également important de noter que l’API Java Persistence (JPA) n’a pas de concept d’objets détachés et réaffectés, et utilise EntityManager.persist () et EntityManager.merge ().

J’ai constaté en général qu’en utilisant Hibernate, saveOrUpdate () suffit généralement à mes besoins. En général, je n'ai besoin d'utiliser la fusion que lorsque des objets peuvent faire référence à des objets du même type. Plus récemment, la cause de l'exception était dans le code validant que la référence n'était pas récursive. Je chargeais le même objet dans ma session dans le cadre de la validation, provoquant l'erreur.

Où avez-vous rencontré ce problème? La fusion a-t-elle fonctionné pour vous ou avez-vous eu besoin d'une autre solution? Préférez-vous toujours utiliser la fusion ou préférez-vous l'utiliser uniquement si nécessaire dans des cas spécifiques?

12
HakunaMatata

J'ai trouvé un bon exemple montrant les différences entre toutes les méthodes de sauvegarde en veille prolongée:

http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example

En bref, selon le lien ci-dessus:

save ()

  • Nous pouvons invoquer cette méthode en dehors d'une transaction. Si nous l'utilisons sans transaction et que nous avons des cascades entre entités, seule l'entité principale est enregistrée, à moins que la session ne soit vidée.
  • Ainsi, s’il existe d’autres objets mappés à partir de l’objet principal, ils sont enregistrés au moment de la validation de la transaction ou lors du vidage de la session.

persist ()

  • Cela ressemble à utiliser save () dans une transaction, donc il est sécurisé et prend en charge tous les objets en cascade.

saveOrUpdate ()

  • Peut être utilisé avec ou sans la transaction, et tout comme save (), si elle est utilisée sans la transaction, les entités mappées ne seront pas enregistrées sans que nous vidions la session.

  • Résultats dans des requêtes d'insertion ou de mise à jour basées sur les données fournies. Si les données sont présentes dans la base de données, la requête de mise à jour est exécutée.

update ()

  • La mise à jour d'Hibernate doit être utilisée lorsque nous savons que nous ne mettons à jour que les informations d'entité. Cette opération ajoute l'objet entité au contexte persistant et les modifications ultérieures sont suivies et enregistrées lorsque la transaction est validée.
  • Par conséquent, même après avoir appelé update, si nous définissons des valeurs dans l'entité, elles seront mises à jour lorsque la transaction sera validée.

fusion ()

  • La fusion Hibernate peut être utilisée pour mettre à jour les valeurs existantes. Cependant, cette méthode crée une copie à partir de l'objet entité transmis et la renvoie. L'objet renvoyé fait partie du contexte persistant et suivi pour toutes les modifications. L'objet transmis n'est pas suivi. C'est la différence majeure avec merge () de toutes les autres méthodes.

Également pour des exemples pratiques de tous ceux-ci, veuillez vous référer au lien que j'ai mentionné ci-dessus, il montre des exemples pour toutes ces différentes méthodes.

5
OutOfMind

En fait, la différence entre les méthodes hibernate save() et persist() dépend de la classe du générateur que nous utilisons.

Si notre classe de générateur est affectée, il n'y a pas de différence entre les méthodes save() et persist(). Parce que générateur 'assigné' signifie, en tant que programmeur, nous devons donner la valeur de clé primaire à enregistrer dans la base de données à droite [espérons que vous connaissez ce concept de générateurs] Dans le cas d'une classe de générateur autre qu'attribuée, supposons si notre nom de classe de générateur est Incrément signifie hibernate it self assignera la valeur de la clé primaire id dans la base de données à droite [autre que le générateur assigné, hibernate ne sert qu'à prendre soin de la valeur de la clé primaire id à mémoriser], donc dans ce cas si nous appelons save() ou persist() méthode puis il insérera normalement l'enregistrement dans la base de données. Mais entendez-vous, la méthode save() peut renvoyer la valeur de la clé primaire id générée par hibernate et nous pouvons le voir par

long s = session.save(k);

Dans ce même cas, persist() ne restituera jamais aucune valeur au client.

5
Hari Krishna

Sachez que si vous appelez une mise à jour sur un objet détaché, une mise à jour sera toujours effectuée dans la base de données, que vous ayez modifié l'objet ou non. Si ce n'est pas ce que vous voulez, vous devriez utiliser Session.lock () avec LockMode.None.

Vous ne devez appeler update que si l'objet a été modifié en dehors de la portée de votre session actuelle (en mode détaché).

2
bernardn

Comme je l'ai expliqué dans cet article , vous devriez préférer les méthodes JPA la plupart du temps et le update pour les tâches de traitement par lots.

Une entité JPA ou Hibernate peut se trouver dans l'un des quatre états suivants:

  • Transitoire (Nouveau)
  • Géré (persistant)
  • Détaché
  • Supprimé (supprimé)

La transition d'un état à l'autre se fait via les méthodes EntityManager ou Session.

Par exemple, JPA EntityManager fournit les méthodes de transition d'état suivantes.

enter image description here

Hibernate Session implémente toutes les méthodes JPA EntityManager et fournit des méthodes de transition d'état d'entité supplémentaires telles que save, saveOrUpdate et update.

enter image description here

Persister

Pour changer l'état d'une entité de transitoire (nouveau) à géré (persistant), nous pouvons utiliser la méthode persist proposée par le JPA EntityManager qui est également héritée par le Hibernate Session.

La méthode persist déclenche un PersistEvent géré par l'écouteur d'événements DefaultPersistEventListener d'Hibernate.

Par conséquent, lors de l'exécution du cas de test suivant:

doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    LOGGER.info(
        "Persisting the Book entity with the id: {}", 
        book.getId()
    );
});

Hibernate génère les instructions SQL suivantes:

CALL NEXT VALUE FOR hibernate_sequence

-- Persisting the Book entity with the id: 1

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

Notez que id est affecté avant de joindre l'entité Book au contexte de persistance actuel. Cela est nécessaire car les entités gérées sont stockées dans une structure Map où la clé est formée par le type d’entité et son identifiant et la valeur est la référence de l’entité. C'est la raison pour laquelle JPA EntityManager et Hibernate Session sont connus sous le nom de cache de premier niveau.

Lors de l'appel de persist, l'entité est uniquement liée au contexte de persistance en cours d'exécution et l'INSERT peut être différé jusqu'à ce que flush soit appelé.

La seule exception est le générateur d'IDENTITY qui déclenche l'INSERT immédiatement, car c'est le seul moyen d'obtenir l'identifiant de l'entité. Pour cette raison, Hibernate ne peut pas insérer d'insertion par lots pour les entités utilisant le générateur IDENTITY. Pour plus de détails sur ce sujet, consultez cet article .

Sauver

La méthode save spécifique à Hibernate est antérieure à JPA et est disponible depuis le début du projet Hibernate.

La méthode save déclenche un SaveOrUpdateEvent géré par l'écouteur d'événements DefaultSaveOrUpdateEventListener d'Hibernate. Par conséquent, la méthode save est équivalente aux méthodes update et saveOrUpdate.

Pour voir comment fonctionne la méthode save, considérons le cas de test suivant:

doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);

    Long id = (Long) session.save(book);

    LOGGER.info(
        "Saving the Book entity with the id: {}", 
        id
    );
});

Lors de l'exécution du scénario de test ci-dessus, Hibernate génère les instructions SQL suivantes:

CALL NEXT VALUE FOR hibernate_sequence

-- Saving the Book entity with the id: 1

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

Comme vous pouvez le constater, le résultat est identique à l'appel à la méthode persist. Cependant, contrairement à persist, la méthode save renvoie l'identifiant de l'entité.

Pour plus de détails, consultez cet article .

Mise à jour

La méthode update, spécifique à Hibernate, est conçue pour contourner le mécanisme de vérification à blanc et forcer la mise à jour d'une entité au moment du vidage.

La méthode update déclenche un SaveOrUpdateEvent géré par l'écouteur d'événements DefaultSaveOrUpdateEventListener d'Hibernate. Par conséquent, la méthode update est équivalente aux méthodes save et saveOrUpdate.

Pour voir comment fonctionne la méthode update, considérons l'exemple suivant qui conserve une entité Book dans une transaction, la modifie alors que l'entité est à l'état détaché et force le UPDATE SQL à l'aide de l'appel de méthode update.

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

LOGGER.info("Modifying the Book entity");

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);

    session.update(_book);

    LOGGER.info("Updating the Book entity");
});

Lors de l'exécution du scénario de test ci-dessus, Hibernate génère les instructions SQL suivantes:

CALL NEXT VALUE FOR hibernate_sequence

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

-- Modifying the Book entity
-- Updating the Book entity

UPDATE 
    book 
SET 
    author = 'Vlad Mihalcea', 
    isbn = '978-9730228236', 
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE 
    id = 1

Notez que le UPDATE est exécuté pendant le vidage du contexte de persistance, juste avant la validation, et c’est pourquoi le Updating the Book entity le message est enregistré en premier.

En utilisant @SelectBeforeUpdate pour éviter les mises à jour inutiles

Maintenant, la mise à jour va toujours être exécutée même si l'entité n'a pas été modifiée pendant l'état détaché. Pour éviter cela, vous pouvez utiliser le @SelectBeforeUpdate Annotation Hibernate qui déclenchera une instruction SELECT qui récupère loaded state qui est ensuite utilisé par le mécanisme de vérification en attente.

Donc, si nous annotons l'entité Book avec le @SelectBeforeUpdate annotation:

@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {

    //Code omitted for brevity
}

Et exécutez le cas de test suivant:

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);

    session.update(_book);
});

Hibernate exécute les instructions SQL suivantes:

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

SELECT 
    b.id,
    b.author AS author2_0_,
    b.isbn AS isbn3_0_,
    b.title AS title4_0_
FROM 
    book b
WHERE 
    b.id = 1

Notez que, cette fois, il n'y a pas de UPDATE exécuté depuis que le mécanisme de vérification en profondeur d'Hibernate a détecté que l'entité n'a pas été modifiée.

SaveOrUpdate

La méthode spécifique à Hibernate saveOrUpdate n'est qu'un alias pour save et update.

La méthode saveOrUpdate déclenche un SaveOrUpdateEvent géré par l'écouteur d'événements DefaultSaveOrUpdateEventListener d'Hibernate. Par conséquent, la méthode update est équivalente aux méthodes save et saveOrUpdate.

Vous pouvez maintenant utiliser saveOrUpdate lorsque vous souhaitez conserver une entité ou forcer un UPDATE, comme illustré dans l'exemple suivant.

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(book);

    return book;
});

_book.setTitle("High-Performance Java Persistence, 2nd edition");

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(_book);
});

Attention au NonUniqueObjectException

Un problème qui peut survenir avec save, update et saveOrUpdate est que si le contexte de persistance contient déjà une référence d'entité avec le même identifiant et du même type que ci-dessous. exemple:

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(book);

    return book;
});

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

try {
    doInJPA(entityManager -> {
        Book book = entityManager.find(
            Book.class, 
            _book.getId()
        );

        Session session = entityManager.unwrap(Session.class);
        session.saveOrUpdate(_book);
    });
} catch (NonUniqueObjectException e) {
    LOGGER.error(
        "The Persistence Context cannot hold " +
        "two representations of the same entity", 
        e
    );
}

Maintenant, lors de l'exécution du scénario de test ci-dessus, Hibernate va lancer un NonUniqueObjectException car le second EntityManager contient déjà une entité Book avec le même identifiant que celui que nous passons à update, et le contexte de persistance ne peut pas contenir deux représentations de la même entité.

org.hibernate.NonUniqueObjectException: 
    A different object with the same identifier value was already associated with the session : [com.vladmihalcea.book.hpjp.hibernate.pc.Book#1]
    at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.Java:651)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.Java:284)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.Java:227)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.Java:92)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.Java:73)
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.Java:682)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.Java:674)

Fusionner

Pour éviter NonUniqueObjectException, vous devez également utiliser la méthode merge proposée par le JPA EntityManager et héritée par le Hibernate Session.

Comme expliqué dans cet article , merge récupère un nouvel instantané d'entité à partir de la base de données s'il n'y a pas de référence d'entité trouvée dans le contexte de persistance, et il copie l'état de l'entité détachée transmise. à la méthode merge.

La méthode merge déclenche un MergeEvent géré par l'écouteur d'événements DefaultMergeEventListener d'Hibernate.

Pour voir comment fonctionne la méthode merge, considérons l'exemple suivant qui conserve une entité Book dans une transaction, la modifie alors que l'entité est à l'état détaché et passe l'entité détachée à merge dans une sous-séquence Persistence Context.

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

LOGGER.info("Modifying the Book entity");

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

doInJPA(entityManager -> {
    Book book = entityManager.merge(_book);

    LOGGER.info("Merging the Book entity");

    assertFalse(book == _book);
});

Lors de l'exécution du scénario de test ci-dessus, Hibernate a exécuté les instructions SQL suivantes:

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

-- Modifying the Book entity

SELECT 
    b.id,
    b.author AS author2_0_,
    b.isbn AS isbn3_0_,
    b.title AS title4_0_
FROM 
    book b
WHERE 
    b.id = 1

-- Merging the Book entity

UPDATE 
    book 
SET 
    author = 'Vlad Mihalcea', 
    isbn = '978-9730228236', 
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE 
    id = 1

Notez que la référence à l'entité renvoyée par merge est différente de celle détachée que nous avons transmise à la méthode merge.

Maintenant, bien que vous préfériez utiliser JPA merge lors de la copie de l’état de l’entité détachée, le supplément SELECT peut être problématique lors de l’exécution d’une tâche de traitement par lots.

Pour cette raison, préférez utiliser update lorsque vous êtes certain qu'aucune référence d'entité n'est déjà attachée au contexte de persistance en cours d'exécution et que l'entité détachée a été modifiée.

Pour plus de détails sur ce sujet, consultez cet article .

Conclusion

Pour conserver une entité, vous devez utiliser la méthode JPA persist. Pour copier l'état de l'entité détachée, il est préférable d'utiliser merge. La méthode update est utile pour les tâches de traitement par lots uniquement. Les save et saveOrUpdate ne sont que des alias pour update et vous ne devriez probablement pas les utiliser du tout.

Certains développeurs appellent save même si l'entité est déjà gérée, mais ceci est une erreur et déclenche un événement redondant car, pour les entités gérées, la commande UPDATE est automatiquement gérée au moment du vidage du contexte de persistance.

Pour plus de détails, consultez cet article .

2
Vlad Mihalcea

Aucune des réponses suivantes n'est correcte. Toutes ces méthodes semblent identiques, mais en pratique, les choses sont complètement différentes. Il est difficile de donner de courts commentaires. Mieux vaut donner un lien vers la documentation complète sur ces méthodes: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html

1
Anton Popovich

Aucune des réponses ci-dessus n'est complète. Bien que Leo Theobald réponse semble la réponse la plus proche.

Le point fondamental est de savoir comment hibernate traite les états des entités et comment il les gère en cas de changement d'état. Tout doit être vu en ce qui concerne les bouffées de chaleur et les commits, ce que tout le monde semble avoir complètement ignoré.

N'UTILISEZ JAMAIS LA MÉTHODE DE SAUVEGARDE DE HIBERNATE. OUBLIEZ QU'IL SOIT MÊME EXISTE À HIBERNATE!

persiste

Comme tout le monde l'a expliqué, Persist fait essentiellement passer une entité d'un état "transitoire" à un état "géré". À ce stade, une neige fondue ou une validation peut créer une instruction insert. Mais l'entité restera toujours dans l'état "Géré". Cela ne change pas avec la couleur.

À ce stade, si vous "persistez" à nouveau, il n'y aura aucun changement. Et il n'y aura plus d'économies si nous essayons de conserver une entité persistante.

Le plaisir commence lorsque nous essayons d'expulser l'entité.

Une expulsion est une fonction spéciale d'Hibernate qui fera passer l'entité de "Gérée" à "Détachée". Nous ne pouvons pas appeler une persistance sur une entité détachée. Si nous faisons cela, alors Hibernate lève une exception et la transaction entière sera annulée lors de la validation.

Fusion vs Mise à jour

Ce sont 2 fonctions intéressantes qui font des choses différentes quand elles sont traitées de différentes manières. Tous deux tentent de faire passer l'entité de l'état "Détaché" à l'état "Géré". Mais faire les choses différemment.

Comprendre un fait que Détaché signifie en quelque sorte un état "hors ligne". et géré signifie l'état "En ligne".

Observez le code ci-dessous:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.merge(entity);

    ses1.delete(entity);

    tx1.commit();

Quand tu fais ça? Que penses-tu qu'il va se passer? Si vous avez dit que cela lèverait une exception, alors vous avez raison. Cela provoquera une exception car la fusion a fonctionné sur l'objet entité, qui est un état détaché. Mais cela ne change pas l'état de l'objet.

Dans l’arrière-plan, la fusion soulèvera une requête de sélection et renverra en principe une copie de l’entité qui est dans un état attaché. Observez le code ci-dessous:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();
    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    HibEntity copied = (HibEntity)ses1.merge(entity);
    ses1.delete(copied);

    tx1.commit();

L'exemple ci-dessus fonctionne parce que la fusion a amené une nouvelle entité dans le contexte qui est à l'état persistant.

Lorsqu'il est appliqué avec Mettre à jour, cela fonctionne bien car la mise à jour n'apporte pas une copie d'une entité telle que la fusion.

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.update(entity);

    ses1.delete(entity);

    tx1.commit();

En même temps, dans la trace de débogage, nous pouvons voir que Update n’a pas soulevé la requête SQL de select like merge.

supprimer

Dans l'exemple ci-dessus, j'ai utilisé delete sans parler de delete. Supprimer fera essentiellement passer l'entité de l'état géré à l'état "supprimé". Et lorsque vidée ou validée, une commande de suppression sera émise.

Cependant, il est possible de ramener l'entité à l'état "géré" à partir de l'état "supprimé" à l'aide de la méthode persist.

J'espère que l'explication ci-dessus a clarifié tous les doutes.

0
Bharat Raj