Comment maintenir la cohérence du cache Hibernate en exécutant deux applications Java ?

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

  •  09-06-2019
  •  | 
  •  

Question

Notre conception a un JVM qui est un jboss/webapp (lecture/écriture) qui est utilisé pour conserver les données via la mise en veille prolongée (en utilisant jpa) dans la base de données.Le modèle comporte 10 à 15 classes persistantes avec 3 à 5 niveaux de profondeur dans les relations.

Nous avons alors une JVM distincte qui est le serveur utilisant ces données.Comme il fonctionne en continu, nous n'avons qu'une seule longue session de base de données (lecture seule).

Il n'y a actuellement aucun cache intra-JVM impliqué - nous signalons donc manuellement un JVM à partir de l'autre.

Désormais, lorsque l'application Web modifie certaines données, elle signale au serveur de recharger les données modifiées.Ce que nous avons découvert, c'est que nous devons dire à hibernate de purger les données, puis de les recharger.Le simple fait d'effectuer une récupération/fusion avec la base de données ne fait pas l'affaire - principalement en ce qui concerne les objets situés à plusieurs niveaux de la hiérarchie.

Avez-vous des idées sur la question de savoir s'il y a quelque chose de fondamentalement faux dans cette conception ou si quelqu'un fait cela et a eu plus de chance en travaillant avec la mise en veille prolongée sur les recharges.

Merci, Chris

Était-ce utile?

La solution

Une session Hibernate charge toutes les données qu'elle lit depuis la base de données dans ce qu'elle appelle le cache de premier niveau.Une fois qu'une ligne est chargée à partir de la base de données, toutes les extractions ultérieures pour une ligne avec le même PK renverront les données de ce cache.De plus, les garanties Hibernate font référence à l'égalité pour les objets avec le même PK au cours d'une seule session.

D'après ce que j'ai compris, votre application serveur en lecture seule ne ferme jamais sa session Hibernate.Ainsi, lorsque la base de données est mise à jour par l'application en lecture-écriture, la session sur le serveur en lecture seule n'est pas au courant du changement.En fait, votre application en lecture seule charge une copie en mémoire de la base de données et utilise cette copie, qui devient obsolète avec le temps.

Le plan d’action le plus simple et le meilleur que je puisse suggérer consiste à fermer et ouvrir des sessions selon les besoins.Cela contourne tout le problème.Les sessions Hibernate sont destinées à être une fenêtre pour une interaction de courte durée avec la base de données.Je suis d'accord qu'il y a un gain de performances en ne rechargeant pas encore et encore le graphique objet ;mais vous devez le mesurer et vous convaincre que cela en vaut la peine.

Une autre option consiste à fermer et rouvrir la session périodiquement.Cela garantit que l'application en lecture seule fonctionne avec des données ne datant pas d'un intervalle de temps donné.Mais il existe certainement une fenêtre dans laquelle l'application en lecture seule fonctionne avec des données obsolètes (bien que la conception garantisse qu'elle obtiendra éventuellement les données à jour).Cela peut être autorisé dans de nombreuses applications : vous devez évaluer votre situation.

La troisième option consiste à utiliser un cache de deuxième niveau mise en œuvre et utiliser des sessions de courte durée.Il existe différents packages de mise en cache qui fonctionnent avec Hibernate avec des avantages et des inconvénients relatifs.

Autres conseils

Chris, je suis un peu confus quant à ta situation.Si je comprends bien, vous disposez à la fois d'une application Web (lecture/écriture) et d'une application autonome (lecture seule ?) utilisant Hibernate pour accéder à une base de données partagée.Les modifications que vous apportez avec l'application Web ne sont pas visibles par l'application autonome.Est-ce correct?

Si tel est le cas, avez-vous envisagé d’utiliser une autre implémentation de cache de deuxième niveau ?Je me demande si vous pourriez utiliser un cache en cluster partagé à la fois par l'application Web et par l'application autonome.Je pense que SwarmCache, intégré à Hibernate, permettra cela, mais je ne l'ai pas essayé moi-même.

En général, cependant, vous devez savoir que le contenu d'un cache donné ne sera jamais informé de l'activité d'une autre application (c'est pourquoi je suggère que les deux applications partagent un cache).Bonne chance!

De mon point de vue, vous devriez remplacer votre cache Hibernate souligné par celui qui prend en charge le mode cluster.Cela pourrait être un Cache JBoss ou un Cache d'essaim.Le premier prend mieux en charge la synchronisation des données (réplication et invalidation) et prend également en charge JTA.

Vous pourrez ensuite configurer la synchronisation du cache entre l'application Web et le serveur.Regardez également le niveau d'isolement si vous utilisez JBoss Cache.Je crois que tu devrais utiliser READ_COMMITTED mode si vous souhaitez obtenir de nouvelles données sur un serveur à partir de la même session.

La pratique la plus utilisée consiste à disposer d'un Gestionnaire d'entités gérées par conteneur afin que deux applications ou plus dans le même conteneur (c'est-à-dire Glassfish, Tomcat, Websphere) puissent partager les mêmes caches.Mais si vous n'utilisez pas de conteneur d'application, parce que vous utilisez Play!par exemple, je créerais des services Web dans le Application principale pour lire/écrire de manière cohérente dans le cache.

Je pense qu’utiliser des données obsolètes est une porte ouverte au désastre.Tout comme les Singletons deviennent des Multitons, les applications en lecture seule sont souvent un écrire parfois.

Ceinture et bretelles :)

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