JPA / Hibernate Persistence Context

1. Áttekintés

A Hibernate-hez hasonló perzisztencia-szolgáltatók a perzisztencia-kontextust használják az entitás életciklusának kezelésére egy alkalmazásban.

Ebben az oktatóanyagban a perzisztencia-kontextus bevezetésével kezdjük, majd meglátjuk, miért fontos. Végül példákkal láthatjuk a különbséget a tranzakciós hatókörű és a kiterjesztett hatókörű perzisztencia-kontextus között.

2. Perzisztencia kontextus

Vessünk egy pillantást a perzisztencia kontextusának hivatalos meghatározására:

Az EntityManager példány társul egy perzisztencia-kontextussal. A perzisztens kontextus olyan entitáspéldányok halmaza, amelyben bármely állandó entitásidentitáshoz egyedi entitáspéldány tartozik. A perzisztencia-környezetben az entitáspéldányokat és azok életciklusát kezelik. Az EntityManager API-t állandó entitáspéldányok létrehozására és eltávolítására, entitások elsődleges kulcsuk alapján történő megkeresésére és entitások lekérdezésére használják.

A fenti állítás most kissé összetettnek tűnhet, de a továbbiakban teljes értelme lesz. A perzisztencia-kontextus az első szintű gyorsítótár, ahol az összes entitást lekérik az adatbázisból, vagy elmentik az adatbázisba. Az alkalmazásunk és a tartós tárolás között helyezkedik el.

A perzisztencia-kontextus nyomon követi a kezelt entitásba történt esetleges változásokat. Ha valami megváltozik egy tranzakció során, akkor az entitást piszkosnak jelöljük. Amikor a tranzakció befejeződik, ezek a változások a tartós tárolóba kerülnek.

A EntityManager az a felület, amely lehetővé teszi számunkra, hogy kölcsönhatásba lépjünk a perzisztencia kontextussal. Bármikor használjuk a EntityManager, valójában kölcsönhatásba lépünk a perzisztencia kontextussal.

Ha az entitásban végrehajtott minden változás felhívja a tartós tárhelyet, elképzelhetjük, hogy hány hívás fog történni. Ez hatással lesz a teljesítményre, mivel a tartós tárhelyhívások drágák.

3. Perzisztencia kontextustípus

A perzisztencia-összefüggések kétféle formában érhetők el:

  • Tranzakció hatókörű perzisztencia összefüggések
  • Kiterjesztett hatókörű perzisztencia-kontextus

Vessünk egy pillantást mindegyikre.

3.1 Tranzakcióköteles perzisztencia kontextus

A tranzakció perzisztenciája összefügg a tranzakcióval. Amint a tranzakció befejeződik, a perzisztens környezetben jelen lévő entitások állandó tárolóba kerülnek.

Amikor bármilyen műveletet végrehajtunk a tranzakción belül, a EntityManager ellenőrzi a perzisztencia összefüggéseit. Ha létezik, akkor használni fogják. Ellenkező esetben perzisztens kontextust hoz létre.

Az alapértelmezett perzisztencia-kontextustípus vanPersistenceContextType.Tranzakció. Elmondani a EntityManager a tranzakció-perzisztencia kontextusának használatához egyszerűen megjegyezzük @PersistenceContext:

@PersistenceContext privát EntityManager entitásManager;

3.2 Kiterjesztett hatókörű perzisztencia-kontextus

A kiterjesztett perzisztencia-kontextus több tranzakcióra is kiterjedhet. Megtarthatjuk az entitást a tranzakció nélkül, de nem tudjuk áthelyezni tranzakció nélkül.

Elmondani EntityManager a kiterjesztett hatókörű perzisztencia-kontextus használatához alkalmaznunk kell a típus attribútuma @PersistenceContext:

@PersistenceContext (type = PersistenceContextType.EXTENDED) private EntityManager entitásManager;

A hontalan munkamenet babban a az egyik komponens kiterjesztett perzisztencia-kontextusa teljesen nincs tudatában egy másik komponens perzisztens kontextusának. Ez akkor is igaz, ha mindkettő ugyanabban a tranzakcióban van.

Tegyük fel, hogy fennmarad valamilyen entitás a Component módszerében A, amely egy tranzakcióban fut. Ezután a Component valamilyen módszerét hívjuk B. Az Alkatrészben B-k metódus perzisztencia kontextusában nem találjuk meg azt az entitást, amelyet korábban a komponens metódusában kitartottunk A.

4. Perzisztencia-kontextus példa

Most, hogy már eléggé tudunk a kitartás kontextusáról, itt az ideje, hogy elmélyüljünk egy példában. Különböző felhasználási eseteket fogunk készíteni tranzakciós perzisztencia és kiterjesztett perzisztencia kontextussal.

Először hozzuk létre a szolgáltatási osztályunkat, TransctionPersistenceContextUserService:

@Component public class TransactionPersistenceContextUserService {@PersistenceContext private EntityManager entitásManager; @Transactional public Felhasználói insertWithTransaction (Felhasználói felhasználó) {entitManager.persist (felhasználó); visszatérő felhasználó; } public User insertWithoutTransaction (Felhasználó felhasználó) {entitManager.persist (felhasználó); visszatérő felhasználó; } public User find (long id) {return entitásManager.find (Felhasználó.osztály, id); }}

A következő osztály, ExtendedPersistenceContextUserService, nagyon hasonlít a fentiekhez, kivéve a @PersistenceContext annotáció. Ezúttal elhaladunk PersistenceContextType.EXTENDED ba,-be típus paramétere @PersistenceContext kommentár:

@Component public class ExtendedPersistenceContextUserService {@PersistenceContext (type = PersistenceContextType.EXTENDED) private EntityManager entitásManager; // fennmaradó kód megegyezik a fentivel}

5. Tesztesetek

Most, hogy beállítottuk a szolgáltatási osztályainkat, itt az ideje, hogy különböző felhasználási eseteket hozzunk létre tranzakciós perzisztencia és kibővített perzisztencia kontextussal.

5.1 A tranzakciós perzisztencia kontextusának tesztelése

Maradjunk fenn a Felhasználó tranzakciós hatókörű perzisztencia-kontextust használó entitás. Az entitás állandó tárolóba kerül. Ezután a kiterjesztett perzisztencia-kontextusunk segítségével keresési hívással ellenőrizzük EntityManager:

Felhasználó felhasználó = új felhasználó (121L, "Devender", "admin"); transctionPersistenceContext.insertWithTransaction (felhasználó); Felhasználó userFromTransctionPersistenceContext = transctionPersistenceContext .find (user.getId ()); assertNotNull (userFromTransctionPersistenceContext); User userFromExtendedPersistenceContext = ExtendedPersistenceContext .find (user.getId ()); assertNotNull (userFromExtendedPersistenceContext);

Amikor megpróbálunk beszúrni egy Felhasználó akkor tranzakció nélküli entitás TransactionRequiredException dobni fogják:

@Test (várható = TransactionRequiredException.class) public void testThatUserSaveWithoutTransactionThrowException () {User user = new User (122L, "Devender", "admin"); transctionPersistenceContext.insertWithoutTransaction (felhasználó); }

5.2 Kiterjesztett perzisztencia-kontextus tesztelése

Ezután tartsuk fenn a felhasználót kiterjesztett perzisztencia-kontextussal és tranzakció nélkül. A Felhasználó Az entitás a perzisztencia-kontextusba (gyorsítótárba) kerül mentésre, de nem a perzisztens tárhelybe:

Felhasználó felhasználó = új felhasználó (123L, "Devender", "admin"); ExtendedPersistenceContext.insertWithoutTransaction (felhasználó); User userFromExtendedPersistenceContext = ExtendedPersistenceContext .find (user.getId ()); assertNotNull (userFromExtendedPersistenceContext); Felhasználó userFromTransctionPersistenceContext = transctionPersistenceContext .find (user.getId ()); assertNull (userFromTransctionPersistenceContext);

Bármely állandó entitásidentitás perzisztens környezetében egyedi entitáspéldány lesz. Ha megpróbálunk fennmaradni egy másik entitással azonos azonosítóval:

@Test (várható = EntityExistsException.class) public void testThatPersistUserWithSameIdentifierThrowException () {User user1 = new User (126L, "Devender", "admin"); User2 = új felhasználó (126L, "Devender", "admin"); ExtendedPersistenceContext.insertWithoutTransaction (user1); ExtendedPersistenceContext.insertWithoutTransaction (user2); }

Meglátjuk EntityExistsException:

javax.persistence.EntityExistsException: Egy másik azonos azonosító értékű objektum már társítva volt a munkamenethez

A tranzakción belüli kibővített perzisztencia-kontextus a tranzakció végén tartós tárolóba menti az entitást:

Felhasználó felhasználó = új felhasználó (127L, "Devender", "admin"); ExtendedPersistenceContext.insertWithTransaction (felhasználó); User userFromDB = transctionPersistenceContext.find (user.getId ()); assertNotNull (userFromDB);

A kibővített kitartási kontextus a gyorsítótárazott entitásokat a tranzakción belüli használatba véve állandó tárolóba vezeti. Először is tranzakció nélkül tartjuk fenn az entitást. Ezután egy másik entitást tartunk fenn a tranzakcióban:

User1 = új felhasználó (124L, "Devender", "admin"); ExtendedPersistenceContext.insertWithoutTransaction (user1); User2 = új felhasználó (125L, "Devender", "admin"); ExtendedPersistenceContext.insertWithTransaction (user2); Felhasználói user1FromTransctionPersistenceContext = transctionPersistenceContext .find (user1.getId ()); assertNotNull (user1FromTransctionPersistenceContext); Felhasználói user2FromTransctionPersistenceContext = transctionPersistenceContext .find (user2.getId ()); assertNotNull (user2FromTransctionPersistenceContext);

6. Következtetés

Ebben az oktatóanyagban jól megértettük a perzisztencia összefüggéseit.

Először a tranzakció fennmaradásának összefüggéseit vizsgáltuk, amely a tranzakció teljes élettartama alatt fennáll. Ezután megvizsgáltuk a kiterjesztett perzisztencia-kontextust, amely több tranzakcióra is kiterjedhet.

Mint mindig, a mintakód elérhető a GitHubon.