JPA / Hibernate Persistent Context

1. Pregled

Pružatelji trajnosti kao što je Hibernate koriste kontekst trajnosti za upravljanje životnim ciklusom entiteta u aplikaciji.

U ovom uputstvu započet ćemo s uvođenjem konteksta postojanosti, a zatim ćemo vidjeti zašto je to važno. Konačno, vidjet ćemo razliku između konteksta trajnosti s opsegom transakcija i konteksta trajnosti s proširenim opsegom s primjerima.

2. Kontekst postojanosti

Pogledajmo službenu definiciju konteksta postojanosti:

Primjer EntityManager povezan je s kontekstom postojanosti. Kontekst postojanosti je skup instanci entiteta u kojem za bilo koji trajni identitet entiteta postoji jedinstvena instanca entiteta. U kontekstu postojanosti upravljaju se instancama entiteta i njihovim životnim ciklusom. API EntityManager koristi se za stvaranje i uklanjanje postojanih instanci entiteta, pronalaženje entiteta prema njihovom primarnom ključu i ispitivanje entiteta.

Gornja se izjava trenutno može činiti pomalo složenom, ali bit će potpuno logična kako nastavljamo. Kontekst postojanosti je predmemorija prve razine u kojoj se svi entiteti dohvaćaju iz baze podataka ili spremaju u bazu podataka. Smješteno je između naše aplikacije i trajne pohrane.

Kontekst postojanosti prati sve promjene napravljene u upravljanom entitetu. Ako se nešto promijeni tijekom transakcije, tada je entitet označen kao prljav. Kada se transakcija dovrši, ove se promjene brišu u trajnu pohranu.

The EntityManager je sučelje koje nam omogućuje interakciju s kontekstom postojanosti. Kad god koristimo EntityManager, mi zapravo komuniciramo s kontekstom postojanosti.

Ako svaka promjena izvršena u entitetu uputi poziv na trajnu pohranu, možemo zamisliti koliko će poziva biti upućeno. To će dovesti do utjecaja na izvedbu jer su trajni pozivi za pohranu skupi.

3. Tip konteksta postojanosti

Konteksti postojanosti dostupni su u dvije vrste:

  • Kontekst trajnosti s opsegom transakcija
  • Prošireni kontekst postojanosti

Pogledajmo svaku.

3.1 Kontekst trajnosti obuhvaćene transakcijom

Kontekst trajnosti transakcije vezan je za transakciju. Čim transakcija završi, entiteti prisutni u kontekstu postojanosti bit će prebačeni u trajnu pohranu.

Kada izvršimo bilo koju operaciju unutar transakcije, EntityManager provjerava kontekst postojanosti. Ako postoji, tada će se koristiti. Inače će stvoriti kontekst postojanosti.

Zadana vrsta konteksta trajnosti jePersistenceContextType.TRANSACTION. Da kažem EntityManager da bismo koristili kontekst trajnosti transakcije, jednostavno ga označavamo s @PersistenceContext:

@PersistenceContext private EntityManager entityManager;

3.2 Prošireni kontekst postojanosti

Prošireni kontekst trajnosti može se proširiti na više transakcija. Entitet možemo ustrajati bez transakcije, ali ga ne možemo isprati bez transakcije.

Reći EntityManager da bismo koristili kontekst postojanosti s proširenim opsegom, moramo primijeniti tip atribut @PersistenceContext:

@PersistenceContext (type = PersistenceContextType.EXTENDED) private EntityManager entityManager;

U grahu sjednice bez državljanstva, prošireni kontekst postojanosti u jednoj komponenti potpuno je nesvjestan nijednog konteksta postojanosti druge komponente. To je točno čak i ako su obje iste transakcije.

Recimo da ustrajemo u nekom entitetu u metodi Component A, koji se izvodi u transakciji. Tada nazivamo neku metodu Component B. U komponenti B-a Kontekst postojanosti metode, nećemo pronaći entitet koji smo prethodno ustrajali u metodi Komponenta A.

4. Primjer konteksta postojanosti

Sad kad znamo dovoljno o kontekstu ustrajnosti, vrijeme je da uronimo u jedan primjer. Napravit ćemo različite slučajeve upotrebe s kontekstom postojanosti transakcija i proširenim kontekstom postojanosti.

Prvo, izradimo našu uslužnu klasu, TransctionPersistenceContextUserService:

@Component javna klasa TransctionPersistenceContextUserService {@PersistenceContext private EntityManager entityManager; @Transactional javni korisnik insertWithTransaction (korisnik korisnik) {entityManager.persist (korisnik); povratni korisnik; } javni korisnik insertWithoutTransaction (korisnik korisnik) {entityManager.persist (korisnik); povratni korisnik; } javno pronalaženje korisnika (dugi id) {return entityManager.find (User.class, id); }}

Sljedeći sat, ExtendedPersistenceContextUserService, je vrlo sličan gore navedenom, osim za @PersistenceContext bilješka. Ovaj put prolazimo PersistenceContextType.EXTENDED u tip parametar svog @PersistenceContext napomena:

@Component javna klasa ExtendedPersistenceContextUserService {@PersistenceContext (type = PersistenceContextType.EXTENDED) private EntityManager entityManager; // Preostali kôd isti kao gore}

5. Ispitni slučajevi

Sada kada imamo postavljene klase usluga, vrijeme je da napravimo različite slučajeve upotrebe s kontekstom postojanosti transakcija i proširenim kontekstom postojanosti.

5.1 Testiranje konteksta trajnosti transakcije

Ustrajmo a Korisnik entitet koji koristi kontekst trajnosti s opsegom transakcija. Entitet će se spremiti u trajnu pohranu. Zatim provjeravamo upućivanjem poziva za pronalaženje pomoću našeg proširenog konteksta postojanosti EntityManager:

Korisnik korisnik = novi korisnik (121L, "Devender", "admin"); transctionPersistenceContext.insertWithTransaction (korisnik); Korisnik userFromTransctionPersistenceContext = transctionPersistenceContext .find (user.getId ()); assertNotNull (userFromTransctionPersistenceContext); Korisnik userFromExtendedPersistenceContext = extendedPersistenceContext .find (user.getId ()); assertNotNull (userFromExtendedPersistenceContext);

Kad pokušamo umetnuti a Korisnik entitet bez transakcije, dakle TransactionRequiredException bit će bačen:

@Test (očekuje se = TransactionRequiredException.class) javna praznina testThatUserSaveWithoutTransactionThrowException () {Korisnik korisnik = novi korisnik (122L, "Devender", "admin"); transctionPersistenceContext.insertWithoutTransaction (korisnik); }

5.2 Testiranje konteksta proširene upornosti

Dalje, ustrajmo u korisniku s proširenim kontekstom trajnosti i bez transakcije. The Korisnik entitet će se spremiti u kontekst trajnosti (predmemorija), ali ne i u trajnu pohranu:

Korisnik korisnik = novi korisnik (123L, "Devender", "admin"); extendedPersistenceContext.insertWithoutTransaction (korisnik); Korisnik userFromExtendedPersistenceContext = extendedPersistenceContext .find (user.getId ()); assertNotNull (userFromExtendedPersistenceContext); Korisnik userFromTransctionPersistenceContext = transctionPersistenceContext .find (user.getId ()); assertNull (userFromTransctionPersistenceContext);

U kontekstu postojanosti za bilo koji trajni identitet entiteta, postojat će jedinstvena instanca instance. Ako pokušamo zadržati drugi entitet s istim identifikatorom:

@Test (očekuje se = EntityExistsException.class) javna praznina testThatPersistUserWithSameIdentifierThrowException () {Korisnik user1 = novi korisnik (126L, "Devender", "admin"); Korisnik user2 = novi korisnik (126L, "Devender", "admin"); extensionPersistenceContext.insertWithoutTransaction (korisnik1); extensionPersistenceContext.insertWithoutTransaction (korisnik2); }

Vidjet ćemo EntityExistsException:

javax.persistence.EntityExistsException: Različiti objekt s istom vrijednošću identifikatora već je pridružen sesiji

Prošireni kontekst trajnosti unutar transakcije sprema entitet u trajnu pohranu na kraju transakcije:

Korisnik korisnik = novi korisnik (127L, "Devender", "admin"); extendedPersistenceContext.insertWithTransaction (korisnik); Korisnik userFromDB = transctionPersistenceContext.find (user.getId ()); assertNotNull (userFromDB);

Prošireni kontekst ustrajnosti ispire predmemorirane entitete u trajnu pohranu kada se koristi u transakciji. Prvo, postojamo u entitetu bez transakcije. Dalje, nastavljamo s drugim entitetom u transakciji:

Korisnik user1 = novi korisnik (124L, "Devender", "admin"); extensionPersistenceContext.insertWithoutTransaction (korisnik1); Korisnik user2 = novi korisnik (125L, "Devender", "admin"); extensionPersistenceContext.insertWithTransaction (korisnik2); Korisnik user1FromTransctionPersistenceContext = transctionPersistenceContext .find (user1.getId ()); assertNotNull (user1FromTransctionPersistenceContext); Korisnik user2FromTransctionPersistenceContext = transctionPersistenceContext .find (user2.getId ()); assertNotNull (user2FromTransctionPersistenceContext);

6. Zaključak

U ovom uputstvu stekli smo dobro razumijevanje konteksta postojanosti.

Prvo smo pogledali kontekst trajnosti transakcije, koji postoji tijekom života transakcije. Zatim smo pogledali prošireni kontekst trajnosti, koji se može proširiti na više transakcija.

Kao i uvijek, uzorak koda dostupan je na GitHubu.