Hibernált második szintű gyorsítótár

1. Áttekintés

Az adatbázis-absztrakciós rétegek, például az ORM (object-relational mapping) keretrendszerek egyik előnye az az adatok átlátható gyorsítótárának képessége az alapul szolgáló boltból szerezték be. Ez segít kiküszöbölni a gyakran hozzáférhető adatok adatbázis-hozzáférési költségeit.

A teljesítménynövekedés jelentős lehet, ha a gyorsítótárazott tartalom olvasási / írási aránya magas, különösen azoknál az entitásoknál, amelyek nagy objektumgrafikonokból állnak.

Ebben a cikkben a Hibernate második szintű gyorsítótárat tárjuk fel.

Megmagyarázunk néhány alapfogalmat, és mint mindig, mindent egyszerű példákkal illusztrálunk. A JPA-t használjuk, és csak azokra a funkciókra térünk vissza a Hibernate natív API-ra, amelyek nincsenek szabványosítva a JPA-ban.

2. Mi a második szintű gyorsítótár?

A legtöbb más, teljesen felszerelt ORM keretrendszerhez hasonlóan a Hibernate is az első szintű gyorsítótár fogalmát képviseli. Ez egy munkamenet hatókörű gyorsítótár, amely biztosítja, hogy minden entitáspéldányt csak egyszer töltsenek be a tartós környezetben.

A munkamenet lezárása után az első szintű gyorsítótár is megszűnik. Ez valójában kívánatos, mivel lehetővé teszi, hogy az egyidejű munkamenetek az entitáspéldányokkal egymástól elkülönítve működjenek.

Másrészt a második szintű gyorsítótár SessionFactory-scoped, ami azt jelenti, hogy ugyanazon munkamenet gyárral létrehozott összes munkamenet megosztja. Amikor az entitáspéldányt az azonosítója keresi (akár alkalmazáslogika, akár belső hibernálás alapján, például. amikor társításokat tölt be az entitáshoz más entitásoktól), és ha a második szintű gyorsítótárazás engedélyezve van az adott entitás számára, a következő történik:

  • Ha egy példány már szerepel az első szintű gyorsítótárban, onnan kerül vissza
  • Ha egy példány nem található az első szintű gyorsítótárban, és a megfelelő példányállapotot a második szintű gyorsítótárban tárolja, akkor az adatokat onnan lehívja, és egy példány összeáll és visszaküldik
  • Ellenkező esetben a szükséges adatok betöltődnek az adatbázisból, és egy példány összeáll és visszakerül

Miután a példány a perzisztencia-kontextusban (első szintű gyorsítótár) van tárolva, onnan kerül vissza minden ugyanazon munkameneten belüli összes következő hívás során, amíg a munkamenet le nem zárul vagy a példány manuálisan ki nem kerül a perzisztencia-kontextusból. Ezenkívül a betöltött példányállapotot az L2 gyorsítótár tárolja, ha még nem volt ott.

3. Régiógyár

A hibernált második szintű gyorsítótár úgy lett kialakítva, hogy ne legyen tisztában a tényleges használt gyorsítótár-szolgáltatóval. A hibernált állapotot csak a org.hibernate.cache.spi.RegionFactory felület, amely a tényleges gyorsítótár-szolgáltatók összes részletét összefoglalja. Alapvetően hídként működik a hibernált és a gyorsítótár-szolgáltatók között.

Ebben a cikkben az Ehcache-t használjuk gyorsítótár-szolgáltatóként, amely kiforrott és széles körben használt gyorsítótár. Természetesen bármely más szolgáltatót választhat, amennyiben van egy RegionFactory érte.

Hozzáadjuk az Ehcache régió gyári megvalósítását az osztályútvonalhoz a következő Maven-függőséggel:

 org.hibernate hibernate-ehcache 5.2.2.Végső 

Itt tekintheti meg a (z) legújabb verzióját hibernate-ehcache. Győződjön meg azonban arról hibernate-ehcache verzió megegyezik a projektben használt hibernált verzióval, például. ha használja hibernate-ehcache 5.2.2.Végső mint ebben a példában, akkor a Hibernate verziójának is annak kell lennie 5.2.2.Döntő.

A hibernate-ehcache az artefaktum függ magától az Ehcache megvalósítástól, amely így átmenetileg benne van az osztálypályában is.

4. A második szintű gyorsítótár engedélyezése

A következő két tulajdonsággal azt mondjuk a hibernáltnak, hogy az L2 gyorsítótárazás engedélyezve van, és megadjuk a régió gyári osztályának nevét:

hibernate.cache.use_second_level_cache = true hibernate.cache.region.factory_class = org.hibernate.cache.ehcache.EhCacheRegionFactory 

Például a kitartás.xml a következőképpen nézne ki:

 ...   ... 

A második szintű gyorsítótár letiltásához (például hibakeresési célokra) csak állítsa be hibernate.cache.use_second_level_cache tulajdonság hamisra.

5. Egy entitás gyorsítótárazása

Azért, hogy tegye alkalmassá az entitást a második szintű gyorsítótárra, a Hibernate specifikusal jegyzeteljük @ org.hibernate.annotations.Cache jelölést és adjon meg egy gyorsítótár-párhuzamossági stratégiát.

Egyes fejlesztők úgy vélik, hogy jó szokás a szabvány hozzáadása @ javax.persistence.Cache annotáció is (bár a hibernálás nem igényli), így az entitásosztály megvalósítása így nézhet ki:

@Entity @Cacheable @ org.hibernate.annotations.Cache (use = CacheConcurrencyStrategy.READ_WRITE) public class Foo {@Id @GeneratedValue (strategy = GenerationType.AUTO) @Column (name = "ID") private long id; @Column (name = "NAME") privát karakterlánc neve; // szerelők és beállítók}

A Hibernate minden entitásosztályhoz külön gyorsítótár-régiót fog használni az adott osztály példányainak állapotához. A régió neve a teljesen minősített osztálynév.

Például, Foo a példányok a megnevezett gyorsítótárban vannak tárolva com.baeldung.hibernate.cache.model.Foo Ehcache-ben.

A gyorsítótár gyors működésének ellenőrzéséhez írhatunk egy ilyen gyors tesztet:

Foo foo = új Foo (); fooService.create (foo); fooService.findOne (foo.getId ()); int méret = CacheManager.ALL_CACHE_MANAGERS.get (0) .getCache ("com.baeldung.hibernate.cache.model.Foo"). getSize (); assertThat (méret, nagyobbThan (0));

Itt közvetlenül az Ehcache API-t használjuk ennek ellenőrzésére com.baeldung.hibernate.cache.model.Foo a gyorsítótár nem üres az a betöltése után Foo példa.

Engedélyezheti a Hibernate által generált SQL naplózását és meghívhatja is fooService.findOne (foo.getId ()) a teszt során többször annak ellenőrzésére, hogy a válassza nyilatkozat a betöltéshez Foo csak egyszer nyomtatja ki (először), ami azt jelenti, hogy a következő hívások során az entitáspéldány lekérésre kerül a gyorsítótárból.

6. Gyorsítótár-párhuzamossági stratégia

Felhasználási esetek alapján szabadon választhatjuk az alábbi gyorsítótár-párhuzamossági stratégiák egyikét:

  • CSAK OLVASHATÓ: Csak olyan entitásoknál használható, amelyek soha nem változnak (kivételt képez, ha megpróbálják frissíteni az ilyen entitást). Nagyon egyszerű és előadói. Nagyon alkalmas olyan statikus referenciaadatokhoz, amelyek nem változnak
  • NONSTRICT_READ_WRITE: A gyorsítótár frissül egy tranzakció végrehajtása után, amely megváltoztatta az érintett adatokat. Így nincs garantálva az erős konzisztencia, és van egy kis időablak, amelyben az elavult adatok a gyorsítótárból nyerhetők. Ez a fajta stratégia alkalmas olyan esetekre, amelyek elviselik az esetleges következetességet
  • ÍR OLVAS: Ez a stratégia erős konzisztenciát garantál, amelyet a „soft” zárak használatával ér el: A gyorsítótárazott entitás frissítésekor az entitás gyorsítótárában is tárolódik egy soft lock, amely a tranzakció végrehajtása után felszabadul. Az összes egyidejűleg végrehajtott tranzakció, amely hozzáférést biztosít a soft lockolt bejegyzésekhez, a megfelelő adatokat közvetlenül az adatbázisból fogja lekérni
  • TRANZAKCIÓS: A gyorsítótár-módosítások elosztott XA tranzakciókban történnek. A gyorsítótárazott entitás változása vagy végrehajtásra kerül, vagy visszavonásra kerül mind az adatbázisban, mind a gyorsítótárban ugyanazon XA tranzakció során

7. Gyorsítótár-kezelés

Ha a lejárati és a kilakoltatási házirendek nincsenek meghatározva, a gyorsítótár a végtelenségig növekedhet, és végül az összes rendelkezésre álló memóriát felemésztheti. A legtöbb esetben a Hibernate az ilyen gyorsítótár-kezelési feladatokat a gyorsítótár-szolgáltatókra bízza, mivel azok valóban az egyes gyorsítótár-megvalósításokra jellemzőek.

Például meghatározhatjuk a következő Ehcache konfigurációt, hogy korlátozzuk a gyorsítótárban tárolt maximális számot Foo példányok 1000-ig:

8. Gyűjtemény gyorsítótár

A gyűjtemények alapértelmezés szerint nincsenek gyorsítótárazottan, és ezeket kifejezetten gyorsítótárként kell megjelölnünk. Például:

@Entity @Cacheable @ org.hibernate.annotations.Cache (use = CacheConcurrencyStrategy.READ_WRITE) public class Foo {... @Cacheable @ org.hibernate.annotations.Cache (use = CacheConcurrencyStrategy.READ_WRITE) @OneToMany collection; // szerelők és beállítók}

9. A gyorsítótárazott állam belső képviselete

Az entitásokat nem második szintű gyorsítótárban tárolják Java példányként, hanem szétszerelt (hidratált) állapotban:

  • Az azonosító (elsődleges kulcs) nincs tárolva (a gyorsítótár kulcs részeként tárolódik)
  • Az átmeneti tulajdonságok nincsenek tárolva
  • A gyűjteményeket nem tároljuk (a részleteket lásd alább)
  • A társítás nélküli tulajdonságértékeket eredeti formájukban tároljuk
  • Csak az id (idegen kulcs) tárolva van Egyhez egyesületek

Ez a Hibernate általános második szintű gyorsítótár-tervezést ábrázolja, amelyben a gyorsítótár-modell az alapul szolgáló relációs modellt tükrözi, amely helytakarékos és megkönnyíti a kettő szinkronizálását.

9.1. A gyorsítótárazott gyűjtemények belső ábrázolása

Már említettük, hogy kifejezetten meg kell jelölnünk, hogy egy gyűjtemény (Egy a sokhoz vagy ManyToMany asszociáció) gyorsítótárazott, különben nincs gyorsítótárban.

Valójában a Hibernate gyűjteményeket külön gyorsítótár-régiókban tárol, minden gyűjteményhez egyet. A régió neve egy teljesen minősített osztálynév, plusz a gyűjtemény tulajdonság neve, például: com.baeldung.hibernate.cache.model.Foo.bars. Ez rugalmasságot biztosít a gyűjtemények külön gyorsítótár-paramétereinek meghatározásához, például. kilakoltatási / lejáratási politika.

Fontos megemlíteni azt is, hogy az egyes gyűjtemény-bejegyzésekhez csak a gyűjteményben található entitások azonosítói kerülnek gyorsítótárba, ami azt jelenti, hogy a legtöbb esetben célszerű a benne lévő entitásokat is gyorsítótárazni.

10. Gyorsítótár érvénytelenítése HQL DML stílusú lekérdezésekhez és natív lekérdezésekhez

Ami a DML stílusú HQL-t illeti (betét, frissítés és töröl HQL utasítások), a hibernált képes meghatározni, hogy mely entitásokat érintik az ilyen műveletek:

entitásManager.createQuery ("Foo frissítés megadva… ahol ..."). executeUpdate ();

Ebben az esetben az összes Foo példányt kitesszük az L2 gyorsítótárból, míg a többi gyorsítótárazott tartalom változatlan marad.

Amikor azonban natív SQL DML utasításokról van szó, a Hibernate nem tudja kitalálni, hogy mi frissül, ezért érvényteleníti a teljes második szintű gyorsítótárat:

session.createNativeQuery ("frissítse a FOO-t… ahol…"). executeUpdate ();

Valószínűleg nem ezt akarja! A megoldás az, hogy elmondja a hibernálásnak, hogy mely entitásokat érintik a natív DML utasítások, hogy csak a Foo entitások:

Query nativeQuery = entitásManager.createNativeQuery ("FOO frissítés beállítása ... ahol ..."); nativeQuery.unwrap (org.hibernate.SQLQuery.class) .addSynchronizedEntityClass (Foo.class); nativeQuery.executeUpdate ();

Túlságosan visszaesett a hibernátus őslakosaihoz SQLQuery API, mivel ez a funkció (még) nincs meghatározva a JPA-ban.

Vegye figyelembe, hogy a fentiek csak a DML utasításokra vonatkoznak (betét, frissítés, töröl és natív függvény / eljárás hívások). Anyanyelvi válassza a lekérdezések nem érvénytelenítik a gyorsítótárat.

11. Lekérdezés gyorsítótár

A HQL lekérdezések eredményei is tárolhatók gyorsítótárba. Ez akkor hasznos, ha gyakran hajt végre lekérdezést ritkán változó entitásokon.

A lekérdezés gyorsítótárának engedélyezéséhez állítsa be az értékét hibernate.cache.use_query_cache tulajdonhoz igaz:

hibernate.cache.use_query_cache = true

Ezután minden lekérdezéshez kifejezetten meg kell jelölnie, hogy a lekérdezés gyorsítótárazott (egy org.hibernate.cache lekérdezési tipp):

entitásManager.createQuery ("válasszon f-et a Foo f-ből") .setHint ("org.hibernate.cacheable", true) .getResultList ();

11.1. Lekérdezés gyorsítótár legjobb gyakorlatok

Íme néhány iránymutatások és a lekérdezés gyorsítótárával kapcsolatos bevált gyakorlatok:

  • A gyűjteményekhez hasonlóan csak a gyorsítótárazott lekérdezés eredményeként visszaadott entitások azonosítói kerülnek gyorsítótárba, ezért erősen ajánlott engedélyezni a második szintű gyorsítótárat az ilyen entitások számára.
  • Minden lekérdezéshez tartozik egy gyorsítótár-bejegyzés a lekérdezési paraméterek (kötési változók) minden egyes kombinációjához, így azok a lekérdezések, amelyekre a paraméterértékek sok különböző kombinációját várják, nem alkalmasak gyorsítótárra.
  • Azok a lekérdezések, amelyek olyan entitásosztályokat tartalmaznak, amelyeknél az adatbázisban gyakran változnak, szintén nem alkalmasak a gyorsítótárra, mert érvénytelenek lesznek, ha változás történik a lekérdezésben részt vevő bármely osztályba tartozó entitással kapcsolatban, függetlenül attól, hogy a megváltozott példányok gyorsítótárazott a lekérdezés eredményének részeként, vagy sem.
  • Alapértelmezés szerint az összes lekérdezés-gyorsítótár eredményt a rendszer tárolja org.hibernate.cache.internal.StandardQueryCache vidék. Az entitás / gyűjtemény gyorsítótárhoz hasonlóan testreszabhatja a régió gyorsítótárának paramétereit, hogy az igényeinek megfelelően meghatározza a kilakoltatási és lejárati házirendeket. Minden lekérdezéshez megadhat egy egyedi régiónevet is annak érdekében, hogy különböző beállításokat biztosítson a különböző lekérdezésekhez.
  • A gyorsítótárazott lekérdezések részeként lekérdezett összes tábla esetében a Hibernate az utolsó frissítés időbélyegzőit külön nevű régióban tartja org.hibernate.cache.spi.UpdateTimestampsCache. Nagyon fontos ennek a régiónak a tudatában lenni, ha a lekérdezés gyorsítótárát használja, mert a hibernált állapot azt használja annak ellenőrzésére, hogy a gyorsítótárazott lekérdezési eredmények nem elavultak-e. Az ebben a gyorsítótárban szereplő bejegyzéseket nem szabad kilakoltatni / lejáratni, amíg a lekérdezés eredményeinek régióiban vannak gyorsítótárazott lekérdezési eredmények a megfelelő táblákhoz. A legjobb, ha kikapcsolja az automatikus kilakoltatást és a lejáratot ennek a gyorsítótár-régiónak, mivel amúgy sem fogyaszt sok memóriát.

12. Következtetés

Ebben a cikkben megvizsgáltuk, hogyan állítsuk be a Hibernate második szintű gyorsítótárát. Láttuk, hogy meglehetősen egyszerű konfigurálni és használni, mivel a Hibernate mindent megtesz a színfalak mögött, így a második szintű gyorsítótár-kihasználás átláthatóvá válik az alkalmazás üzleti logikája szempontjából.

A Hibernate Second Level Cache Tutorial megvalósítása elérhető a Githubon. Ez egy Maven-alapú projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.