Voici ma compréhension des méthodes. Ils sont principalement basés sur l' API, car je ne les utilise pas tous dans la pratique.
saveOrUpdate Les
appels sont enregistré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.
save
Persiste une entité. Attribuera un identifiant s'il n'en existe pas. Si tel est le cas, il s'agit essentiellement d'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 pense 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 C'est
maintenant que ma connaissance commence à faiblir. L'important ici est la différence entre les entités transitoires, détachées et persistantes. Pour plus d'informations sur les états des objets, jetez un œil ici . Avec save & update, vous traitez avec des objets persistants. Ils sont liés à une session afin qu'Hibernate sache ce qui a changé. Mais lorsque vous avez un objet transitoire, aucune session n'est impliquée. Dans ces cas, vous devez utiliser la fusion pour les mises à jour et persister pour l'enregistrement.
persist
Comme mentionné ci-dessus, il est utilisé sur les objets transitoires. Il ne renvoie pas l'ID généré.
la source
update
un objet transitoire est très bien, je n'ai pas eu d'exception.Voir le Forum Hibernate pour une explication des différences subtiles entre persist et save. Il semble que la différence soit le 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). Persist n'exécutera aucune instruction en dehors de la transaction en cours d'exécution uniquement pour attribuer l'identifiant. Save / Persist fonctionnent tous les deux sur des instances transitoires , c'est-à-dire des instances auxquelles aucun identifiant n'est encore attribué et en tant que telles ne sont pas enregistrées dans la base de données.
La mise à jour et la fusion fonctionnent toutes les deux sur des instances détachées , c'est-à-dire des instances qui ont une entrée correspondante dans la base de données mais qui ne sont actuellement pas attachées (ou gérées par) une session. La différence entre eux est ce qui arrive à l'instance qui est passée à la fonction. update essaie de rattacher l'instance, cela signifie qu'il ne doit pas y avoir d'autre instance de l'entité persistante attachée à la session pour le moment, sinon une exception est levée. la fusion , cependant, copie simplement toutes les valeurs dans une instance persistante de la session (qui sera chargée si elle n'est pas actuellement chargée). L'objet d'entrée n'est pas modifié. La fusion est donc plus générale que la mise à jour, mais peut utiliser plus de ressources.
la source
save() - If an INSERT has to be executed to get the identifier, then this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is problematic in a long-running conversation with an extended Session/persistence context.
Pouvez-vous s'il vous plaît me dire comment un insert peut se produire en dehors d'une session et pourquoi est-ce mauvais?INSERT
éditée. Par conséquent, dans ces cas, vous ne pouvez pas renvoyer un identifiant maintenant sans l'avoir généré et pour le générer, vous devez exécuterINSERT
maintenant . Depuis, une transaction de longue durée n'est pas exécutée en ce moment mais uniquement lors de la validation, la seule façon d'exécuter leINSERT
maintenant est de l'exécuter en dehors du tx.Ce lien explique bien:
http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/
Nous avons tous ces problèmes que nous rencontrons assez rarement pour que lorsque nous les revoyons, nous savons que nous avons résolu ce problème, mais je ne me souviens pas comment.
La NonUniqueObjectException levée lors de l'utilisation de Session.saveOrUpdate () dans Hibernate est l'une des miennes. Je vais ajouter de nouvelles fonctionnalités à une application complexe. Tous mes tests unitaires fonctionnent bien. Puis, en testant l'interface utilisateur, en essayant d'enregistrer un objet, je commence à obtenir une exception avec le message "un objet différent avec la même valeur d'identifiant était déjà associé à la session." Voici un exemple de code de Java Persistence avec Hibernate.
Pour comprendre la cause de cette exception, il est important de comprendre les objets détachés et ce qui se passe 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 que nous voulons le mettre à jour, nous devons rattacher l'objet. Au cours de ce processus de rattachement, 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. Peut-être que d'autres modifications ont été apportées à ces autres copies que nous prévoyons d'enregistrer, mais Hibernate ne les connaît pas, car il ne les gérait pas à l'époque.
Plutôt que d'enregistrer des données potentiellement mauvaises, Hibernate nous parle 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 force Hibernate à copier toutes les modifications d'autres instances détachées sur l'instance que vous souhaitez enregistrer, et fusionne donc toutes les modifications en mémoire avant l'enregistrement.
Il est important de noter que la fusion renvoie une référence à la nouvelle 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 retourne false dans ce cas. Vous voudrez probablement travailler avec l'élément3 à partir de ce point.
Il est également important de noter que l'API Java Persistence (JPA) n'a pas de concept d'objets détachés et réattachés et utilise EntityManager.persist () et EntityManager.merge ().
J'ai trouvé en général que lorsque vous utilisez Hibernate, saveOrUpdate () est généralement suffisant pour mes besoins. Je n'ai généralement besoin d'utiliser la fusion que lorsque j'ai des objets qui 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 selon les besoins pour des cas spécifiques
la source
En fait, la différence entre la mise en veille prolongée
save()
et lespersist()
méthodes dépend de la classe de générateur que nous utilisons.Si notre classe de générateur est affectée, il n'y a aucune différence entre les méthodes
save()
etpersist(
). Parce que le générateur «assigné» signifie, en tant que programmeur, nous devons donner la valeur de clé primaire à enregistrer dans la bonne base de données [J'espère que vous connaissez ce concept de générateur] Dans le cas d'une classe de générateur autre que celle affectée, supposez que si le nom de notre classe de générateur est Increment signifie hibernate it self assignera la valeur de l'identifiant de la clé primaire dans le droit de la base de données [autre que le générateur assigné, hibernate n'est utilisé que pour prendre soin de la valeur de l'identifiant de la clé primaire rappelez-vous], donc dans ce cas, si nous appelonssave()
ou lapersist()
méthode, il insérera l'enregistrement dans la base de données normalement Mais écoutez, lasave()
méthode peut retourner cette valeur d'ID de clé primaire qui est générée par hibernate et nous pouvons la voir parDans ce même cas,
persist()
ne restituera jamais aucune valeur au client.la source
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:
enregistrer()
persister()
saveOrUpdate ()
Peut être utilisé avec ou sans la transaction, et tout comme save (), s'il est utilisé sans la transaction, les entités mappées ne seront pas enregistrées sans; nous vidons la session.
Résultats dans les requêtes d'insertion ou de mise à jour en fonction des données fournies. Si les données sont présentes dans la base de données, une requête de mise à jour est exécutée.
mettre à jour()
fusionner()
Aussi pour des exemples pratiques de tout cela, veuillez vous référer au lien que j'ai mentionné ci-dessus, il montre des exemples pour toutes ces différentes méthodes.
la source
Comme je l'ai expliqué dans cet article , vous devriez préférer les méthodes JPA la plupart du temps et les
update
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, le JPA
EntityManager
fournit les méthodes de transition d'état d'entité suivantes.Hibernate
Session
implémente toutes lesEntityManager
méthodes JPA et fournit des méthodes de transition d'état d'entité supplémentaires commesave
,saveOrUpdate
etupdate
.Persister
Pour changer l'état d'une entité de Transitoire (Nouveau) à Géré (Persistant), nous pouvons utiliser la
persist
méthode proposée par le JPAEntityManager
qui est également héritée par l'HibernateSession
.Par conséquent, lors de l'exécution du scénario de test suivant:
Hibernate génère les instructions SQL suivantes:
Notez que le
id
est attribué avant d'attacher l'Book
entité au contexte de persistance actuel. Cela est nécessaire car les entités gérées sont stockées dans uneMap
structure où la clé est formée par le type d'entité et son identifiant et la valeur est la référence d'entité. C'est la raison pour laquelle le JPAEntityManager
et le HibernateSession
sont connus comme le cache de premier niveau.Lors de l'appel
persist
, l'entité est uniquement attachée au contexte de persistance en cours d'exécution et l'insertion peut être différée jusqu'à ce que l'flush
appel soit effectué.La seule exception est le générateur IDENTITY qui déclenche immédiatement INSERT car c'est la seule façon d'obtenir l'identifiant d'entité. Pour cette raison, Hibernate ne peut pas traiter par lots des insertions pour les entités utilisant le générateur IDENTITY. Pour plus de détails sur ce sujet, consultez cet article .
sauver
La
save
méthode spécifique à Hibernate est antérieure à JPA et elle est disponible depuis le début du projet Hibernate.Pour voir comment fonctionne la
save
méthode, considérez le cas de test suivant:Lors de l'exécution du scénario de test ci-dessus, Hibernate génère les instructions SQL suivantes:
Comme vous pouvez le voir, le résultat est identique à l'
persist
appel de méthode. Cependant, contrairement àpersist
, lasave
méthode renvoie l'identifiant d'entité.Pour plus de détails, consultez cet article .
Mettre à jour
La
update
méthode spécifique à Hibernate est destinée à contourner le mécanisme de vérification incorrecte et à forcer une mise à jour d'entité au moment du vidage.Pour voir comment fonctionne la
update
méthode, considérez l'exemple suivant qui persiste uneBook
entité dans une transaction, puis il la modifie pendant que l'entité est à l'état détaché et force la mise à jour SQL à l'aide de l'update
appel de méthode.Lors de l'exécution du scénario de test ci-dessus, Hibernate génère les instructions SQL suivantes:
Notez que le
UPDATE
est exécuté pendant le vidage du contexte de persistance, juste avant la validation, et c'est pourquoi leUpdating the Book entity
message est enregistré en premier.Utilisation
@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 lorsqu'elle était à l'état détaché. Pour éviter cela, vous pouvez utiliser l'
@SelectBeforeUpdate
annotation Hibernate qui déclenchera uneSELECT
instruction récupéréeloaded state
qui sera ensuite utilisée par le mécanisme de vérification sale.Donc, si nous annotons l'
Book
entité avec l'@SelectBeforeUpdate
annotation:Et exécutez le scénario de test suivant:
Hibernate exécute les instructions SQL suivantes:
Notez que, cette fois, il n'y a pas d'
UPDATE
exécutions puisque le mécanisme de vérification sale Hibernate a détecté que l'entité n'a pas été modifiée.SaveOrUpdate
La
saveOrUpdate
méthode spécifique à Hibernate n'est qu'un alias poursave
etupdate
.Maintenant, vous pouvez utiliser
saveOrUpdate
lorsque vous souhaitez conserver une entité ou forcer uneUPDATE
comme illustré par l'exemple suivant.Méfiez-vous des
NonUniqueObjectException
Un problème qui peut se produire avec
save
,update
etsaveOrUpdate
est si le contexte de persistance contient déjà une référence d'entité avec le même ID et du même type que dans l'exemple suivant:Maintenant, lors de l'exécution du scénario de test ci-dessus, Hibernate va lancer un
NonUniqueObjectException
car le secondEntityManager
contient déjà uneBook
entité avec le même identifiant que celui vers lequel nous passonsupdate
, et le contexte de persistance ne peut pas contenir deux représentations de la même entité.Fusionner
Pour éviter cela
NonUniqueObjectException
, vous devez utiliser lamerge
méthode proposée par la JPAEntityManager
et héritée également par l'HibernateSession
.Comme expliqué dans cet article , le
merge
récupère un nouvel instantané d'entité 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 passée à lamerge
méthode.Pour voir comment fonctionne la
merge
méthode, considérez l'exemple suivant qui persiste uneBook
entité dans une transaction, puis il la modifie pendant que l'entité est à l'état détaché et passe l'entité détachée àmerge
dans un contexte de persistance de sous-séquence.Lors de l'exécution du scénario de test ci-dessus, Hibernate a exécuté les instructions SQL suivantes:
Notez que la référence d'entité renvoyée par
merge
est différente de celle détachée que nous avons passée à lamerge
méthode.Maintenant, bien que vous préfériez utiliser JPA
merge
lors de la copie de l'état d'entité détachée, le supplémentSELECT
peut être problématique lors de l'exécution d'une tâche de traitement par lots.Pour cette raison, vous devriez préférer utiliser
update
lorsque vous êtes sûr 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
persist
méthode JPA . Pour copier l'état de l'entité détachée,merge
doit être préféré. Laupdate
méthode est utile pour les tâches de traitement par lots uniquement. Lessave
et nesaveOrUpdate
sont que des aliasupdate
et vous ne devriez probablement pas les utiliser du tout.Certains développeurs appellent
save
même lorsque l'entité est déjà gérée, mais c'est une erreur et déclenche un événement redondant car, pour les entités gérées, la MISE À JOUR est automatiquement gérée au moment du vidage du contexte de persistance.Pour plus de détails, consultez cet article .
la source
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 devez utiliser Session.lock () avec LockMode.None.
Vous ne devez appeler la mise à jour que si l'objet a été modifié en dehors de la portée de votre session actuelle (en mode détaché).
la source
Aucune des réponses suivantes n'est correcte. Toutes ces méthodes semblent être similaires, mais en pratique, elles font des choses absolument différentes. Il est difficile de faire de brefs commentaires. Mieux vaut donner un lien vers une documentation complète sur ces méthodes: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html
la source
Aucune des réponses ci-dessus n'est complète. Bien que la réponse de Leo Theobald ressemble à 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 également, ce que tout le monde semble avoir complètement ignoré.
N'UTILISEZ JAMAIS LA MÉTHODE SAUVEGARDE D'HIBERNATION. OUBLIEZ QU'IL EXISTE MÊME EN HIBERNATION!
Persister
Comme tout le monde l'a expliqué, Persist fait essentiellement la transition d'une entité de l'état "Transitoire" à l'état "Géré". À ce stade, un slush ou un commit peut créer une instruction d'insertion. Mais l'entité restera toujours dans l'état "Géré". Cela ne change pas avec flush.
À ce stade, si vous "Persistez" à nouveau, il n'y aura aucun changement. Et il n'y aura plus d'économies si nous essayons de faire persister 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 un persist sur une entité détachée. Si nous le faisons, Hibernate déclenche une exception et la transaction entière est annulée lors de la validation.
Fusion vs mise à jour
Ce sont 2 fonctions intéressantes qui font des choses différentes lorsqu'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 le faire différemment.
Comprenez le fait que Détaché signifie une sorte d'état "hors ligne". et géré signifie état "En ligne".
Observez le code ci-dessous:
Quand tu fais ça? Que penses-tu qu'il va se passer? Si vous avez dit que cela déclencherait une exception, alors vous avez raison. Cela déclenchera une exception car, la fusion a fonctionné sur l'objet entité, qui est l'état détaché. Mais cela ne modifie pas l'état de l'objet.
Dans les coulisses, la fusion déclenche une requête de sélection et renvoie essentiellement une copie de l'entité qui est dans un état attaché. Observez le code ci-dessous:
L'exemple ci-dessus fonctionne parce que la fusion a amené une nouvelle entité dans le contexte qui est dans un état persistant.
Lorsqu'il est appliqué avec Update, le même fonctionne bien car la mise à jour n'apporte pas réellement une copie d'entité comme la fusion.
Dans le même temps, dans la trace de débogage, nous pouvons voir que Update n'a pas soulevé de requête SQL de sélection comme fusion.
supprimer
Dans l'exemple ci-dessus, j'ai utilisé la suppression sans parler de la suppression. La suppression fera essentiellement passer l'entité de l'état géré à l'état "supprimé". Et lorsqu'elle est vidée ou validée, elle émet une commande de suppression à stocker.
Cependant, il est possible de ramener l'entité à l'état "géré" de l'état "supprimé" à l'aide de la méthode persist.
J'espère que l'explication ci-dessus a clarifié tous les doutes.
la source