Pourquoi avez-vous besoin d'un cache de requêtes

Réécrivons notre exemple en obtenant des employés dans HQL :

Employee director1 = session.createQuery("from Employee where id = 4").uniqueResult();
Employee director2 = session.createQuery("from Employee where id = 4").uniqueResult();

assertTrue(director1 != director2);

Les résultats de ces requêtes ne sont stockés ni par le cache de premier ni de second niveau.

C'est exactement là que le cache de requêtes peut être utilisé . Il est également désactivé par défaut. Pour l'activer, ajoutez la ligne suivante au fichier de configuration :

<property name="hibernate.cache.use_query_cache" value="true"/>

Mais ce n'est que la moitié de la solution. Nous avons activé le cache de requête, mais nous devons également spécifier les résultats de requête que nous voulons mettre en cache. Ceci doit être écrit dans la requête :

Query query = session.createQuery("from Employee where id = 4");
query.setCacheable(true);
Employee director1 = query.uniqueResult();

Le cache de requêtes est similaire à un cache de second niveau. Mais, contrairement à lui, ici la clé des données du cache n'est pas l'identifiant de l'objet, mais l'ensemble des paramètres de la requête. Et les données elles-mêmes sont les identifiants des objets qui correspondent aux critères de requête. Ainsi, il est rationnel d'utiliser ce cache avec le cache de second niveau.

Vider le cache

L'une des tâches importantes lorsque vous travaillez avec un cache est de vous assurer que les objets mis en cache changent et de les supprimer du cache (ou de les mettre à jour). Hibernate le fait très bien. Parfois, il semble même qu'il soit guidé par la règle "vider le cache dans toute situation incompréhensible".

Supposons que vous souhaitiez mettre à jour les données utilisateur via HQL :

Query query = session.createQuery("update Employee set name=’Alex’ where id = 4")
query. executeUpdate();

Hibernate ne peut pas savoir exactement ce qui a changé dans la base de données, mais il sait que vous modifiez un objet Employee. Par conséquent, après avoir exécuté cette requête, Hibernate supprimera tous les objets de type Employee de son cache.

Mais NativeQuery fonctionne encore plus intéressant :

Query nativeQuery = session.createNativeQuery("update employee set name=’Alex’ where id = 4")
nativeQuery.executeUpdate();

Une requête SQL native vers la base de données a été exécutée. Cela signifie que quelque chose a changé dans la base de données - la requête a été appelée dans la méthode executeUpdate() . Par conséquent, dans ce cas, Hibernate jouera la sécurité et supprimera tous les objets de tous types de son cache .

Comment aimez-vous ça? Vous appelez une requête inoffensive et Hibernate en réponse efface toutes les données du cache ! C'est certainement mieux que s'il gardait des objets qui diffèrent de la base, mais c'est tout !

Par conséquent, les créateurs d'Hibernate ont rapidement compris comment aider Hibernate dans ce cas. Vous pouvez lui dire quel type d'entité supprimer du cache :

Query nativeQuery = session.createNativeQuery("update employee set name=’Alex’ where id = 4");
nativeQuery.unwrap(org.hibernate.SQLQuery.class).addSynchronizedEntityClass(Employee.class);
nativeQuery.executeUpdate();
Remarque . Les requêtes de sélection natives ne vident pas le cache , seulement insèrent, mettent à jour, suppriment, appellent des procédures, etc.

Vidage manuel du cache

Pour certaines raisons, vous pouvez supprimer vous-même un objet du cache. Cela peut se faire de différentes façons.

Remarque . Les objets du cache sont stockés dans des groupes appelés régions . Par défaut, le nom de la région est le même que le nom de la classe. Par conséquent, si vous avez des objets de type com.codegym.Employee , ils seront tous stockés dans un groupe (région) avec le nom « com.codegym.employee ».

Si vous souhaitez accéder au cache et en faire quelque chose, vous pouvez le faire avec l'objet SessionFactory et la méthode getCache() :

session.getSessionFactory().getCache().evictQueryRegion("com.codegym.employee”);

Si vous souhaitez supprimer les données de tous les groupes (régions), vous devez exécuter la requête suivante :

session.getSessionFactory().getCache().evictAllRegions();

Pour supprimer un objet du cache, vous devez passer son nom (type) et son identifiant. Vous pouvez le faire de deux manières :

session.getSessionFactory().getCache().evictEntityData("Employee, 4);

session.getSessionFactory().getCache().evictEntityData(com.codegym.Employee.class, 4);

Vous pouvez également vérifier si un objet particulier est dans le cache :

session.getSessionFactory().getCache().containsEntity("Employee, 4);
session.getSessionFactory().getCache().containsEntity(com.codegym.Employee.class, 4);