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()
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é.
╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║ 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 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.
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?
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 ()
persist ()
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 ()
fusion ()
É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.
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.
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é).
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:
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.
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
.
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 unPersistEvent
géré par l'écouteur d'événementsDefaultPersistEventListener
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 .
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 unSaveOrUpdateEvent
géré par l'écouteur d'événementsDefaultSaveOrUpdateEventListener
d'Hibernate. Par conséquent, la méthodesave
est équivalente aux méthodesupdate
etsaveOrUpdate
.
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 .
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 unSaveOrUpdateEvent
géré par l'écouteur d'événementsDefaultSaveOrUpdateEventListener
d'Hibernate. Par conséquent, la méthodeupdate
est équivalente aux méthodessave
etsaveOrUpdate
.
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.
@SelectBeforeUpdate
pour éviter les mises à jour inutilesMaintenant, 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.
La méthode spécifique à Hibernate saveOrUpdate
n'est qu'un alias pour save
et update
.
La méthode
saveOrUpdate
déclenche unSaveOrUpdateEvent
géré par l'écouteur d'événementsDefaultSaveOrUpdateEventListener
d'Hibernate. Par conséquent, la méthodeupdate
est équivalente aux méthodessave
etsaveOrUpdate
.
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);
});
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)
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 unMergeEvent
géré par l'écouteur d'événementsDefaultMergeEventListener
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 .
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 .
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
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.