Varför du behöver en frågecache

Låt oss skriva om vårt exempel med att få anställda i HQL:

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

assertTrue(director1 != director2);

Resultaten av sådana frågor lagras inte av varken första eller andra nivåns cache.

Det är precis där frågecachen kan användas . Den är också inaktiverad som standard. För att aktivera det, lägg till följande rad i konfigurationsfilen:

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

Men detta är bara halva lösningen. Vi har aktiverat frågecachen, men vi måste också ange vilka frågeresultat vi vill cache. Detta måste skrivas i frågan:

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

Frågecachen liknar en andra nivås cache. Men, till skillnad från det, här är nyckeln till cachedata inte objektidentifieraren, utan uppsättningen frågeparametrar. Och själva data är identifierarna för de objekt som matchar frågekriterierna. Därför är det rationellt att använda denna cache med den andra nivåns cache.

Rensa cachen

En av de viktiga uppgifterna när man arbetar med en cache är att se till att cachade objekt ändras och ta bort dem från cachen (eller uppdatera dem). Hibernate gör detta mycket bra. Ibland verkar det till och med som att han styrs av regeln "rensa cachen i alla obegripliga situationer."

Låt oss säga att du vill uppdatera användardata via HQL:

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

Hibernate kan inte veta exakt vad som har ändrats i databasen, men det vet att du ändrar ett Employee-objekt. Därför kommer Hibernate, efter att ha kört den här frågan, att ta bort alla objekt av typen Employee från dess cache.

Men NativeQuery fungerar ännu mer intressant:

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

En inbyggd SQL-fråga till databasen har körts. Det betyder att något har ändrats i databasen - begäran anropades i metoden executeUpdate() . Därför, i det här fallet, kommer Hibernate att spela det säkert och ta bort alla objekt av alla typer från dess cache .

Vad tycker du om det? Du ringer en ofarlig begäran och Hibernate som svar raderar all data från cachen! Det här är säkert bättre än om han höll föremål som skiljer sig från basen, men det är det!

Därför kom skaparna av Hibernate snabbt på hur de skulle hjälpa Hibernate i det här fallet. Du kan tala om vilken enhetstyp som ska tas bort från cachen:

Query nativeQuery = session.createNativeQuery("update employee set name=’Alex’ where id = 4");
nativeQuery.unwrap(org.hibernate.SQLQuery.class).addSynchronizedEntityClass(Employee.class);
nativeQuery.executeUpdate();
Anmärkning . Inbyggda urvalsfrågor rensar inte cacheminnet , bara infogar, uppdaterar, tar bort, proceduranrop, etc.

Manuell cacherensning

Av vissa skäl kanske du vill ta bort ett objekt från cachen själv. Detta kan göras på olika sätt.

Obs ! Objekt i cachen lagras i grupper som kallas regioner . Som standard är regionnamnet detsamma som klassnamnet. Därför, om du har objekt av typen com.codegym.Employee , kommer alla att lagras i en grupp (region) med namnet " com.codegym.employee " .

Om du vill komma åt cachen och göra något med den kan du göra det med SessionFactory-objektet och metoden getCache() :

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

Om du vill ta bort data från alla grupper (regioner) måste du köra följande fråga:

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

För att ta bort ett objekt från cachen måste du skicka dess namn (typ) och id. Du kan göra detta på två sätt:

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

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

Du kan också kontrollera om ett visst objekt finns i cachen:

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