Stratégies de concurrence

Après avoir activé la mise en cache de second niveau dans Hibernate, vous devez expliquer à Hibernate quels objets Entity nous voulons mettre en cache et comment.

Pour ce faire, Hibernate a une annotation spéciale pour les classes Entity - @Cache . Exemple:

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)

Cette annotation doit être écrite pour chaque entité Entity pour laquelle nous voulons utiliser le cache de second niveau. Exemple:

@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee {
    @Id
    private Integer id;
    private Set<Task> tasks;
}

Hibernate a 4 stratégies d'accès possibles pour une entité mise en cache si elle est accessible depuis différents threads :

  • lecture seulement
  • lire écrire
  • lecture-écriture non stricte
  • transactionnel

Lecture seule. Une stratégie de concurrence adaptée aux données qui ne change jamais. Hibernate stockera simplement ces objets dans sa mémoire. Utilisez-le uniquement pour les données de référence.

Les bases de données stockent beaucoup d'informations qui ne changent jamais. Par exemple, une table conserve une liste d'événements qui sont seulement ajoutés mais jamais modifiés ou supprimés. Si vous devez travailler avec cette table via Hibernate, la stratégie de mise en cache en lecture seule vous conviendra.

Lecture-écriture (lecture-écriture). Utilisez cette stratégie pour les données principalement lisibles. Cependant, Hibernate suivra les tentatives de modification de ces données, bien qu'il s'attende à ce qu'elles soient très peu fréquentes.

Vous devez mettre en cache principalement les objets qui changent rarement et qui sont souvent lus/demandés. Si vous avez de tels objets, vous devez utiliser la stratégie de lecture-écriture pour eux.

Lecture-écriture non stricte . Cette stratégie ne garantit pas la cohérence entre le cache et la base de données. Utilisez cette stratégie si les données ne changent presque jamais et qu'un faible risque de données obsolètes n'est pas un problème critique.

Contrairement à la stratégie de lecture-écriture, cette stratégie suppose que les données modifiables ne sont pas verrouillées pour la lecture. Cela peut entraîner la modification de l'objet à un endroit, tandis qu'à un autre, quelqu'un lit l'ancienne version de celui-ci.

Par exemple, un utilisateur a modifié son commentaire, mais les autres utilisateurs voient encore son ancienne version pendant un certain temps. Si cela ne vous pose pas de problème, utilisez la stratégie de lecture-écriture non stricte.

Transactionnel . Utilisez cette stratégie pour les données principalement en lecture seule lorsqu'il est important d'empêcher les données obsolètes dans les transactions simultanées lors des rares occasions de mise à jour.

Stockage des données dans un cache

Un autre détail important concernant le cache de second niveau dont vous devez vous souvenir est qu'Hibernate ne stocke pas les objets de vos classes eux-mêmes. Il stocke les informations sous forme de tableaux de chaînes, de nombres, etc.

Et l'identifiant d'objet agit comme un pointeur vers cette information. Conceptuellement, cela ressemble à une carte, dans laquelle l'identifiant de l'objet est la clé et les tableaux de données sont la valeur. Vous pouvez l'imaginer comme ceci :

1 -> { "Ivanov", 1, null , {1,2,5} }
2 -> { "Petrov", 2, null , {1,2,5} }
3 -> { "Sidorov", 3, null , {1,2,5} }

Ce qui est très raisonnable compte tenu de la quantité de mémoire supplémentaire occupée par chaque objet.

En plus de ce qui précède, vous devez vous rappeler que les dépendances de votre classe Entity ne sont pas non plus mises en cache par défaut. Par exemple, si nous considérons la classe ci-dessus, Employee , lors de la récupération, la collection de tâches sera extraite de la base de données , et non du cache de second niveau .

Si vous souhaitez également mettre en cache les dépendances, la classe devrait ressembler à ceci :

@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee {
    @Id
    private Integer id;

   @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
   private Set<Task> tasks;
}

Et le dernier détail - la lecture à partir du cache de deuxième niveau ne se produit que si l'objet souhaité n'a pas été trouvé dans le cache de premier niveau.

CacheMode

Hibernate permet une gestion très flexible de la mise en cache. Vous pouvez définir le mode de cache pour chaque session individuelle ou même pour chaque demande de base de données.

Il existe cinq modes de ce type :

  • OBTENIR
  • IGNORER
  • NORMAL
  • METTRE
  • RAFRAÎCHIR

Le tableau ci-dessous décrit leur travail :

CacheMode Description
OBTENIR Les données sont lues à partir du cache mais n'y sont pas ajoutées.
IGNORER La session n'interagit pas avec le cache.
NORMAL Les données sont lues à partir du cache et y sont ajoutées.
METTRE Les données ne sont jamais extraites du cache, mais y sont ajoutées.
RAFRAÎCHIR Les données ne sont jamais extraites du cache, mais y sont ajoutées. Dans ce mode, le paramètre hibernate.cache.use_minimal_puts est également utilisé.

Exemple de configuration du mode cache pour une session :

session.setCacheMode(CacheMode.GET);
Employee director = session.createQuery("from Employee where id = 4").uniqueResult();

Et aussi un exemple de réglage du mode pour la session et la requête :

session.setCacheMode(CacheMode.GET);
Query query = session.createQuery("from Employee where id = 4");
query.setCacheMode(CacheMode.IGNORE); // Ignore cache work for this request
Employee director = query.uniqueResult();