web-dev-qa-db-fra.com

Hibernate saveOrUpdate, comportement

Quelqu'un sait-il comment Hibernate sait s'il faut INSÉRER ou METTRE À JOUR une valeur dans la base de données lorsque session.saveOrUpdate() est appelée?

Jusqu'à présent, j'ai uniquement déterminé que cela ne dépend pas des informations contenues dans le cache et que l'existence de l'entité dans la base de données est déterminée par la clé primaire.

40
iliaden

Lorsque vous utilisez .saveOrUpdate() Hibernate vérifiera si l'objet est transitoire (il n'a pas de propriété d'identifiant) et si c'est le cas, il le rendra persistant en lui générant l'identifiant et en l'affectant à la session. Si l'objet a déjà un identifiant, il exécutera .update().

De la documentation :

saveOrUpdate () effectue les opérations suivantes:

  • si l'objet est déjà persistant dans cette session, ne faites rien
  • si un autre objet associé à la session a le même identifiant, lève une exception
  • si l'objet n'a pas de propriété identifiant, enregistrez-le ()
  • si l'identifiant de l'objet a la valeur attribuée à un objet nouvellement instancié, enregistrez-le ()
  • si l'objet est versionné par un ou, et que la valeur de la propriété de version est la même valeur attribuée à un objet nouvellement instancié, enregistrez () sinon mettez à jour () l'objet
41
Rihards

Il est peut-être utile de citer la Bible Hibernate ( Java Persistence with Hibernate, 2nd ed. , page 528):

Les utilisateurs d'Hibernate plus expérimentés utilisent exclusivement saveOrUpdate(); il est beaucoup plus facile de laisser Hibernate décider ce qui est nouveau et ce qui est ancien, en particulier dans un réseau plus complexe d'objets à état mixte. Le seul inconvénient (pas vraiment sérieux) de l'exclusif saveOrUpdate() est qu'il ne peut parfois pas deviner si une instance est ancienne ou nouvelle sans tirer un SELECT sur la base de données - par exemple, lorsqu'une classe est mappé avec une clé composite naturelle et aucune propriété de version ou d'horodatage.

Comment Hibernate détecte-t-il les instances anciennes et les nouvelles? Une gamme d'options est disponible. Hibernate suppose qu'une instance est une instance transitoire non enregistrée si:

  • La propriété d'identifiant est null.
  • La propriété de version ou d'horodatage (si elle existe) est null.
  • Une nouvelle instance de la même classe persistante, créée par Hibernate en interne, a les mêmes valeurs d'identifiant de base de données que l'instance donnée.
  • Vous fournissez un unsaved-value Dans le document de mappage pour la classe, et la valeur de la propriété d'identificateur correspond. L'attribut unsaved-value Est également disponible pour les éléments de mappage de version et d'horodatage.
  • Les données d'entité avec la même valeur d'identifiant ne sont pas dans le cache de deuxième niveau.
  • Vous fournissez une implémentation ou org.hibernate.Interceptor Et renvoyez Boolean.TRUE À partir de Interceptor.isUnsaved() après avoir vérifié l'instance dans votre code.
10
jhegedus

Comme indiqué ici , saveOrUpdate enregistre une instance transitoire en générant un nouvel identifiant ou met à jour/rattache les instances détachées associées à son identifiant actuel. Plus précisément, il le fait:

  • si l'objet est déjà persistant dans cette session, ne faites rien
  • si un autre objet associé à la session a le même identifiant, lève une exception
  • si l'objet n'a pas de propriété d'identifiant, save() it
  • si l'identifiant de l'objet a la valeur attribuée à un objet nouvellement instancié, enregistrez-le ()
  • si l'objet est versionné par un <version> ou <timestamp>, et que la valeur de la propriété version est
  • la même valeur attribuée à un objet nouvellement instancié, save() il
  • sinon update() l'objet
2
bpgergo

Si quelqu'un n'est pas vraiment compris en théorie, il y a un code

MyModel sent = myDao.myDaoImpl(id); 

if(sent == null){                        
    sent = **new MyModel();** // new Object
    sent.setXX(id);
    sent.setYY("Yes");
    sent.setDate(new Date());
    myDao.saveOrUpdate(sent); // Insert will be called
} else if(! "Yes".equalsIgnoreCase(sent.getFlag())) {
    sent.setXX("Yes");
    sent.setDate(new Date());
    myDao.saveOrUpdate(sent); // Update will be called
}
1
Jaikrat

Cela se fait en fonction de la valeur de la clé primaire. Si la clé primaire n'est pas définie, sa valeur par défaut sera 0 pour les clés de substitution numériques et save sera exécuté. Si la clé primaire est remplie, elle invoquera un update.

1
Olaf