Quand et comment utiliser le cache de deuxième niveau d'hibernation?

90

J'ai du mal à comprendre quand la mise en veille prolongée atteint le cache de deuxième niveau et quand cela invalide-t-il le cache.

Voici ce que je comprends actuellement:

  • Le cache de deuxième niveau stocke les entités entre les sessions, la portée est la SessionFactory
  • Vous devez dire quelles entités mettre en cache, aucune entité ne sera mise en cache par défaut
  • Le cache des requêtes stocke les résultats des requêtes dans le cache.

Ce que je ne comprends pas, c'est

  • Quand la mise en veille prolongée atteint-elle ce cache?
  • Disons que j'ai configuré le cache de deuxième niveau mais pas la mise en cache des requêtes. Je veux mettre en cache mes clients, il y en a 50000. De quelles manières puis-je récupérer les clients du cache?
  • Je suppose que je peux les obtenir par identifiant à partir du cache. Ce serait facile mais pas digne de la mise en cache. Mais que faire si je veux faire des calculs avec tous mes clients. Disons que je souhaite afficher une liste des clients, comment puis-je y accéder?
  • Comment puis-je obtenir tous mes clients si la mise en cache des requêtes est désactivée?
  • Que se passerait-il si quelqu'un mettait à jour l'un des clients?
    • Ce client serait-il invalidé dans le cache ou tous les clients seraient-ils invalidés?

Ou est-ce que je pense que la mise en cache est totalement erronée? Quelles seraient les utilisations les plus appropriées du cache de deuxième niveau dans ce cas? La documentation de mise en veille prolongée n'est pas du tout claire sur le fonctionnement du cache dans la réalité. Il n'y a que des instructions sur la façon de le configurer.

Mise à jour: J'ai donc compris que le cache de deuxième niveau (sans cache de requête) serait bon pour charger des données par identifiant. Par exemple, j'ai un objet utilisateur pour lequel je souhaite vérifier les autorisations dans chaque demande d'une application Web. Serait-ce un bon cas pour réduire l'accès à la base de données en mettant l'utilisateur en cache dans le cache de deuxième niveau? Comme si je stockais l'identifiant de l'utilisateur dans la session ou n'importe où et quand je devais vérifier les autorisations, je chargerais l'utilisateur par son identifiant et vérifierais les autorisations.

palto
la source

Réponses:

100

Tout d'abord, parlons du cache de niveau processus (ou cache de 2e niveau comme ils l'appellent dans Hibernate). Pour que cela fonctionne, vous devez

  1. configurer le fournisseur de cache
  2. indiquez à hibernate quelles entités mettre en cache (directement dans le fichier hbm.xml si vous utilisez ce type de mappage).

Vous indiquez au fournisseur de cache le nombre d'objets qu'il doit stocker et quand / pourquoi ils doivent être invalidés. Supposons donc que vous ayez un livre et une entité auteur, chaque fois que vous les récupérez de la base de données, seuls ceux qui ne sont pas dans le cache seront sélectionnés à partir de la base de données. Cela augmente considérablement les performances. C'est utile quand:

  • Vous écrivez dans la base de données uniquement via Hibernate (car il faut un moyen de savoir quand changer ou invalider les entités dans le cache)
  • Vous lisez souvent des objets
  • Vous avez un seul nœud et vous n'avez pas de réplication. Sinon, vous devrez répliquer le cache lui-même (utilisez des caches distribués comme JGroups), ce qui ajoute plus de complexité et ne s'adapte pas aussi bien que les applications sans partage.

Alors, quand le cache fonctionne-t-il?

  • Lorsque vous session.get()ou session.load()l'objet qui a été précédemment sélectionné et réside dans le cache. Le cache est un stockage où ID est la clé et les propriétés sont les valeurs. Donc, ce n'est que lorsqu'il y a une possibilité de recherche par ID que vous pouvez éviter de toucher la base de données.
  • Lorsque vos associations sont chargées paresseusement (ou chargées avec des sélections au lieu de jointures)

Mais cela ne fonctionne pas quand:

  • Si vous ne sélectionnez pas par ID. Encore une fois - le cache de deuxième niveau stocke une carte des identifiants d'entités avec d'autres propriétés (il ne stocke pas réellement les objets, mais les données elles-mêmes), donc si votre recherche ressemble à ceci:, from Authors where name = :namealors vous n'atteignez pas le cache.
  • Lorsque vous utilisez HQL (même si vous utilisez where id = ?).
  • Si vous définissez dans votre mappage fetch="join", cela signifie que pour charger des associations, les jointures seront utilisées partout au lieu d'instructions de sélection séparées. Le cache de niveau de processus ne fonctionne sur les objets enfants que s'il fetch="select"est utilisé.
  • Même si vous en avez, fetch="select"mais dans HQL, vous utilisez des jointures pour sélectionner des associations - ces jointures seront émises immédiatement et elles remplaceront tout ce que vous avez spécifié dans hbm.xml ou les annotations.

Maintenant, à propos du cache de requêtes. Vous devez noter qu'il ne s'agit pas d'un cache séparé, mais d'un ajout au cache de niveau processus. Disons que vous avez une entité Pays. C'est statique, vous savez donc qu'à chaque fois, il y aura le même jeu de résultats lorsque vous dites from Country. C'est un candidat parfait pour le cache de requêtes, il stockera une liste d' identifiants en lui-même et la prochaine fois que vous sélectionnerez tous les pays, il renverra cette liste dans le cache de niveau processus et ce dernier, à son tour, renverra des objets pour chaque identifiant car ces objets sont déjà stockés dans le cache de 2e niveau. Le cache des requêtes est invalidé chaque fois que tout élément lié à l'entité change. Supposons que vous soyez configuré from Authorspour être placé dans un cache de requêtes. Cela ne sera pas efficace car l'auteur change souvent.

Stanislav Bashkyrtsev
la source
Est-ce que la requête «de l'auteur une extraction jointe a.books» nécessite le cache de requêtes pour extraire les auteurs du cache?
palto
1
Non, le cache de requêtes est uniquement destiné aux données statiques et ne stocke que les ID. Les auteurs seront extraits du cache de 2e niveau.
Stanislav Bashkyrtsev
@ctapobep: pas vrai ce que vous dites! "from Author a fetch join a.books" fonctionne bien si les carnets de terrain de l'entité Author sont annotés (récupère EAGER) ... il est trop tard je pense
Bilal BBB
Une si bonne réponse! Je m'en souviendrai tout le temps! : d
Mohammadreza Khatami
après avoir activé le «cache de requête», récupère-t-il les données du cache si vous sélectionnez par une autre propriété que id?
Arun Raaj
42
  • le cache de 2e niveau est un magasin clé-valeur. Cela ne fonctionne que si vous obtenez vos entités par identifiant
  • le cache de 2e niveau est invalidé / mis à jour par entité lorsqu'une entité est mise à jour / supprimée via la mise en veille prolongée. Il n'est pas invalidé si la base de données est mise à jour d'une manière différente.
  • pour les requêtes (par exemple la liste des clients), utilisez le cache de requêtes.

En réalité, il est utile d'avoir un cache distribué clé-valeur - c'est ce qu'est Memcached, et il alimente Facebook, Twitter et bien d'autres. Mais si vous n'avez pas de recherche par identifiant, cela ne sera pas très utile.

Bozho
la source
12

En retard à la fête mais a voulu systématiquement répondre à ces questions que se posent de nombreux développeurs.

Voici ma réponse en prenant votre question une par une.

Q. Quand la mise en veille prolongée atteint-elle ce cache?

A. Le cache de premier niveau est associé à l' objet Session . Le cache de deuxième niveau est associé à l' objet Session Factory . Si l'objet n'est pas trouvé dans le premier, le deuxième niveau est vérifié.

Q. Disons que j'ai configuré le cache de deuxième niveau mais pas la mise en cache des requêtes. Je veux mettre en cache mes clients, il y en a 50000. De quelles manières puis-je récupérer les clients du cache?

R. Vous avez obtenu cette réponse dans votre mise à jour. De plus, le cache de requêtes stocke uniquement la liste des ID de l'objet et ces objets avec leurs ID sont stockés dans le même cache de deuxième niveau. Donc, si vous activez le cache de requêtes, vous utiliserez la même ressource. Neat non?

Q. Je suppose que je peux les obtenir par identifiant à partir du cache. Ce serait facile mais pas digne de la mise en cache. Mais que faire si je veux faire des calculs avec tous mes clients. Disons que je souhaite afficher une liste des clients, comment puis-je y accéder?

A. Répondu ci-dessus.

Q. Comment puis-je obtenir tous mes clients si la mise en cache des requêtes est désactivée?

A. Répondu ci-dessus.

Q. Que se passerait-il si quelqu'un mettait à jour l'un des clients? Ce client serait-il invalidé dans le cache ou tous les clients seraient-ils invalidés?

R. Hibernate n'a aucune idée, mais vous pouvez utiliser d'autres caches IMDG / distribués tiers pour être implémentés en tant que cache de deuxième niveau d'hibernation et les invalider. par exemple, TayzGrid est l'un de ces produits et il y en a plus, je suppose.

Basit Anwer
la source
0

Le cache de deuxième niveau Hibernate est un peu difficile à comprendre et à implémenter. Voici ce que nous pouvons dire en fonction de vos questions:

Quand Hibernate atteint-il ce cache?

Comme vous le suggérez, le cache Hibernate L2 (s'il est activé; il n'est pas activé par défaut) est interrogé uniquement après le cache L1. Il s'agit d'un cache clé-valeur dont les données sont conservées sur plusieurs sessions.

Disons que j'ai configuré le cache de deuxième niveau mais pas la mise en cache des requêtes. Je veux mettre en cache mes clients, il y en a 50000. De quelles manières puis-je récupérer les clients du cache?

La mise en cache des requêtes serait la meilleure pour ce cas d'utilisation, car les données client sont statiques et extraites d'une base de données relationnelle.

Que se passerait-il si quelqu'un mettait à jour l'un des clients? Ce client serait-il invalidé dans le cache ou tous les clients seraient-ils invalidés?

Cela dépend de la stratégie de cache Hibernate spécifique que vous utilisez. Hibernate a en fait quatre stratégies de cache différentes:

READ_ONLY : les objets ne changent pas une fois dans le cache.

NONSTRICT_READ_WRITE : les objets changent (éventuellement) après la mise à jour de l'entrée de base de données correspondante; cela garantit une cohérence éventuelle.

READ_WRITE : les objets changent (immédiatement) après la mise à jour de l'entrée de base de données correspondante; cela garantit une forte cohérence grâce à l'utilisation de verrous «souples».

TRANSACTIONNEL : les objets changent à l'aide de transactions XA distribuées, garantissant l'intégrité des données; cela garantit un succès total ou l'annulation de tous les changements. Dans ces quatre cas, cependant, la mise à jour d'une seule entrée de base de données n'invaliderait pas la liste complète des clients dans le cache. Hibernate est un peu plus intelligent que ça :)

Pour en savoir plus sur le fonctionnement de la mise en cache L2 dans Hibernate, vous pouvez consulter l'article «Qu'est-ce que le cache Hibernate L2» ou l'article détaillé Caching in Hibernate with Redis

Nikita Koksharov
la source