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

StackOverflow https://stackoverflow.com/questions/161224

  •  03-07-2019
  •  | 
  •  

Question

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 les suivantes:

  • save ()
  • update ()
  • saveOrUpdate ()
  • saveOrUpdateCopy ()
  • merge ()
  • persist ()
Était-ce utile?

La solution

Voici ma compréhension des méthodes. Celles-ci sont principalement basées sur la API ne les utilisez pas tous dans la pratique.

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, la mise à jour est appelée.

enregistrer 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é.

mettre à jour Essaie de persister l'entité en utilisant 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 ...

fusion Maintenant, c’est là que 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, ici . Avec save & amp; mettre à jour, vous avez affaire à 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 ce cas, vous devez utiliser la fusion pour les mises à jour et conserver pour la sauvegarde.

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

Autres conseils

╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║    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()         ║
║              ║                               ║                                ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝
  • Voir le Forum Hibernate pour une explication des différences subtiles entre persister et sauver. La différence semble correspondre au moment où l'instruction INSERT est finalement exécutée. Étant donné que 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. Save / Persist fonctionne tous les deux sur des instances transitoires , c’est-à-dire des instances auxquelles aucun identificateur n’a encore été attribué et qui ne sont donc pas enregistrées dans la base de données.

  • La mise à jour et la Fusionner fonctionnent toutes deux sur des instances détachées , c'est-à-dire des instances ayant une entrée correspondante dans la base de données, mais actuellement en cours. non attaché à (ou géré 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 générée. fusion , toutefois, 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.

Ce lien explique de manière pertinente:

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

Nous avons tous les problèmes que nous rencontrons assez rarement, mais lorsque nous les reverrons, nous savons que nous avons résolu ce problème, mais nous ne pouvons pas nous en souvenir.

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. Puis, en testant l'interface utilisateur et en essayant de sauvegarder un objet, je commence à recevoir une exception avec le message "# 8220; un autre objet avec le même identifiant a déjà été associé à la session". Voici quelques exemples de code provenant de Java Persistence avec 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 pas ce que sont les & # 8220; véritables & # 8221; la copie est plus. 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 elle ne les gérait pas à ce moment-là.

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

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 l’instance à enregistrer, et fusionnera donc toutes les modifications en mémoire avant l’enregistrement.

        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 par exemple l'égalité (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 JPA (Java Persistence API) 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 () suffisait 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, confirmant que la référence n’était pas récursive. Je chargeais le même objet dans ma session lors 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 lorsque cela est nécessaire pour des cas spécifiques

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 assignée, il n'y a pas de différence entre les méthodes save () et persist (). Parce que le terme «assigné» au générateur 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'affectée, supposons que si notre nom de classe de générateur est Incrément, cela signifie que l'hibernation lui-même assignera la valeur de la clé primaire id à la base de données [autre que le générateur affecté, hibernate uniquement utilisé pour prendre en compte la valeur de la clé primaire ], donc dans ce cas si nous appelons la méthode save () ou persist () , alors l'enregistrement sera inséré normalement 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 que nous pouvons voir par

long s = session.save(k);

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

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.
  • Par conséquent, 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.

persister ()

  • Son utilisation est similaire à l'utilisation de save () dans une transaction. Il est donc sécurisé et prend en charge tous les objets en cascade.

saveOrUpdate ()

  • Peut être utilisé avec ou sans transaction, et tout comme save (), si elle est utilisée sans transaction, les entités mappées ne seront pas enregistrées tant que nous n'aurons pas vidé 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 Hibernate doit être utilisée lorsque nous savons que nous ne mettons à jour que les informations sur l'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é la mise à jour, 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’entité entité transmise 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.

Pour des exemples pratiques de tous ces exemples, veuillez vous reporter au lien que j’ai mentionné ci-dessus. Vous y trouverez des exemples pour toutes ces différentes méthodes.

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é ou non l'objet. 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é).

Comme je l'ai expliqué dans cet article , vous devrait 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 être dans l'un des quatre états suivants:

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

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

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

 entrer la description de l'image ici

La session Hibernate 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 mettre à jour .

 entrer la description de l'image ici

Persister

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

  

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

Par conséquent, lors de l'exécution du scénario 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 attribué 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 dans laquelle la clé est formée par le type d'entité et son identificateur et la valeur est la référence de l'entité. C’est la raison pour laquelle JPA EntityManager et la session Hibernate Session sont appelés le 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 le flush soit appelé.

La seule exception est le générateur d'IDENTITE , qui déclenche l'INSERT tout de suite puisque c'est la seule façon 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. .

Enregistrer

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 Hibernate DefaultSaveOrUpdateEventListener . 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 . .

Mettre à jour

La méthode update spécifique à Hibernate est conçue pour contourner le mécanisme de vérification incorrect et force la mise à jour de l'entité au moment du vidage.

  

La méthode update déclenche un SaveOrUpdateEvent géré par l'écouteur d'événements Hibernate DefaultSaveOrUpdateEventListener . 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, puis la modifie tant que l'entité est à l'état détaché, et il force le SQL UPDATE en utilisant 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, c'est pourquoi le message Mise à jour de l'entité Livre est d'abord consigné.

Utilisation de @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 l’annotation Hibernate @SelectBeforeUpdate qui déclenchera une instruction SELECT qui récupère l’état chargé , qui est ensuite utilisé par le fichier sale. mécanisme de vérification.

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

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

    //Code omitted for brevity
}

Et exécutez le scénario 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-ci, UPDATE n'est pas exécuté depuis que le mécanisme de vérification incorrecte d'Hibernate a détecté que l'entité n'a pas été modifiée.

SaveOrUpdate

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

  

La méthode saveOrUpdate déclenche un SaveOrUpdateEvent géré par l'écouteur d'événements Hibernate DefaultSaveOrUpdateEventListener . 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 une 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);
});

Faites attention à la NonUniqueObjectException

Un des problèmes pouvant survenir avec save , update et saveOrUpdate est 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 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"
);

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 une exception NonUniqueObjectException car le second EntityManager contient déjà une entité Livre avec identifiant identique à 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 l’exception NonUniqueObjectException , vous devez utiliser la méthode merge proposée par JPA EntityManager et héritée de la session Hibernate . également.

Comme expliqué dans cet article , la fusion extrait un nouvel instantané d'entité de la base de données si aucune référence d'entité ne se trouve dans le contexte de persistance, et 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 Hibernate.

Pour voir comment fonctionne la méthode fusion , considérons l'exemple suivant qui conserve une entité Book dans une transaction, puis la modifie tant que l'entité est à l'état détaché, et passez l'entité détachée à fusionner dans un contexte de persistance de sous-séquence.

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 d'entité renvoyée par fusion est différente de celle détachée que nous avons transmise à la méthode fusion .

Maintenant, bien que vous préfériez utiliser JPA fusion lors de la copie de l'état de l'entité détachée, le SELECT supplémentaire 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 fusion . La méthode update est utile uniquement pour les tâches de traitement par lots. save et saveOrUpdate ne sont que des alias de 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 puisque, 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 . .

Aucune des réponses suivantes n'est exacte. Toutes ces méthodes semblent identiques, mais en pratique, les choses sont absolument 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

Aucune des réponses ci-dessus n'est complète. Bien que la réponse de Leo Theobald 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, que tout le monde semble avoir complètement ignorés.

N'UTILISEZ JAMAIS LA MÉTHODE DE SAUVEGARDE DE HIBERNATE. OUBLIEZ QU'IL SOIT MIS EN HIBERNATE!

Persister

Comme tout le monde l’a expliqué, Persist transite fondamentalement une entité de "Transient". indiquer l'état " Géré " Etat. À ce stade, une neige fondue ou une validation peut créer une instruction insert. Mais l'entité restera toujours dans " Géré " Etat. Cela ne change pas avec la couleur.

À ce stade, si vous "maintenez" " encore une fois, il n'y aura pas de changement. Et il n’y aura plus de sauvegarde 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é". sur "Détaché". 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 / mise à jour

Ce sont 2 fonctions intéressantes qui font des choses différentes quand elles sont traitées de différentes manières. Deux d'entre eux essaient de faire la transition de l'entité de "Détaché" indiquer l'état " Géré " Etat. Mais faire les choses différemment.

Comprenez le fait que Détaché signifie en quelque sorte un "hors connexion". Etat. et géré signifie " En ligne " état.

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 faites-vous cela? 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.

Derrière la scène, la fusion soulève une requête de sélection et renvoie essentiellement une copie de l'entité dont l'état est 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 car la fusion a introduit une nouvelle entité dans le contexte qui est à l'état persistant.

Lorsqu'il est appliqué avec Mettre à jour, la même chose fonctionne, 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é à " enlevé " Etat. Et quand vider ou valider émettra une commande de suppression à stocker.

Toutefois, il est possible de ramener l'entité à "gérée". Etat de " retiré " état en utilisant la méthode persist.

Espérons que l'explication ci-dessus clarifie les doutes.

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