web-dev-qa-db-fra.com

Comment Hibernate décide de l'ordre de mise à jour / insertion / suppression

Oublions d'abord Hibernate. Supposons que j'ai deux tables, A et B. Deux transactions mettent à jour les mêmes enregistrements dans ces deux tables, mais txn 1 met à jour B puis A, tandis que txn 2 met à jour A puis B. Il s'agit d'un exemple de blocage typique. La façon la plus courante d'éviter cela est de prédéfinir l'ordre d'acquisition des ressources. Par exemple, nous devons mettre à jour le tableau A puis B.

Retournez à Hibernate. Lorsque nous mettons à jour de nombreuses entités en une seule session, une fois que je vide la session, les modifications de différentes entités vont générer des instructions d'insertion/mise à jour/suppression correspondantes dans DB. Hibernate a-t-il un algorithme pour décider de l'ordre de mise à jour entre les entités? Sinon, comment Hibernate a-t-il utilisé pour éviter la situation de blocage décrite au 1er paragraphe?

Si Hibernate maintient la commande, comment puis-je connaître ou contrôler la commande? Je ne veux pas que ma mise à jour explicite dans les conflits de base de données avec Hibernate, et provoque un blocage.

33
Adrian Shum

Le problème que vous décrivez n'est pas géré par la base de données, et d'après mon expérience, il n'est pas entièrement géré par Hibernate non plus.

Vous devez prendre des mesures explicites pour éviter que cela ne soit un problème.

Hibernate fait une partie du travail pour vous. Comme indiqué dans la réponse précédente, Hibernate garantit qu'au sein d'une vidange isolée, les insertions, les suppressions et les mises à jour sont ordonnées de manière à garantir qu'elles seront appliquées dans un ordre réalisable. Voir performExecutions (session EventSource) dans la classe AbstractFlushingEventListener:

Exécutez toutes les commandes SQL (et les mises à jour du cache de deuxième niveau) dans un ordre spécial afin que les contraintes de clé étrangère ne puissent pas être violées:

  1. Inserts, dans l'ordre où ils ont été effectués
  2. Mises à jour
  3. Suppression des éléments de collection
  4. Insertion d'éléments de collection
  5. Supprime, dans l'ordre où elles ont été effectuées

Lorsque vous avez des contraintes uniques, il est très important de connaître cet ordre, surtout si vous souhaitez remplacer un enfant un-à-plusieurs (supprimer l'ancien/insérer le nouveau) mais que l'ancien et le nouvel enfant partagent les mêmes contraintes uniques (par exemple, la même adresse e-mail ). Dans ce cas, vous pouvez mettre à jour l'ancienne entrée, au lieu de supprimer/insérer, ou vous pouvez vider après suppression uniquement pour ensuite continuer l'insertion. Pour un exemple plus détaillé, vous pouvez vérifier cet article .

Notez qu'il ne spécifie pas l'ordre des mises à jour. L'examen du code Hibernate m'amène à penser que l'ordre de mise à jour dépendra de l'ordre dans lequel les entités ont été ajoutées au contexte de persistance, [~ # ~] pas [~ # ~] l'ordre dans lequel ils ont été mis à jour. Cela peut être prévisible dans votre code, mais la lecture du code Hibernate ne m'a pas donné le sentiment de me fier à cette commande.

Il y a trois solutions auxquelles je peux penser:

  1. Essayez de définir hibernate.order_updates pour être vrai. Cela devrait permettre d'éviter les interblocages lorsque plusieurs lignes de la même table sont mises à jour, mais n'aidera pas les interblocages sur plusieurs tables.
  2. Faites en sorte que vos transactions prennent un PESSIMISTIC_WRITE verrou sur l'une des entités avant de faire des mises à jour. L'entité que vous utiliserez dépendra de votre situation spécifique, mais tant que vous vous assurez qu'une entité est choisie de manière cohérente en cas de risque de blocage, cela bloquera le reste de la transaction jusqu'à ce que le verrou puisse être obtenu.
  3. Écrivez votre code pour intercepter les blocages lorsqu'ils surviennent et réessayez de manière raisonnable. Le composant gérant la nouvelle tentative de blocage doit être situé en dehors de la limite de transaction actuelle. En effet, la session ayant échoué doit être fermée et la transaction associée annulée. Dans cet article vous pouvez trouver un exemple d'un aspect AOP de nouvelle tentative automatique.
37
David Edwards