Hibernate Entity Lifecycle

1. Overzicht

Elke Hibernate-entiteit heeft natuurlijk een levenscyclus binnen het raamwerk - het is ofwel in een tijdelijke, beheerde, ontkoppelde of verwijderde staat.

Het begrijpen van deze toestanden op zowel conceptueel als technisch niveau is essentieel om Hibernate correct te kunnen gebruiken.

Bekijk een van onze eerdere tutorials voor meer informatie over verschillende Hibernate-methoden die met entiteiten te maken hebben.

2. Hulpmethoden

In deze tutorial zullen we consequent verschillende hulpmethoden gebruiken:

  • HibernateLifecycleUtil.getManagedEntities (sessie) - we gebruiken het om alle beheerde entiteiten van een Sessie interne winkel
  • DirtyDataInspector.getDirtyEntities () - we gaan deze methode gebruiken om een ​​lijst te krijgen van alle entiteiten die zijn gemarkeerd als ‘vuil '
  • HibernateLifecycleUtil.queryCount (query) - een handige methode om te doen tellen (*) query tegen de ingesloten database

Alle bovenstaande hulpmethoden worden statisch geïmporteerd voor betere leesbaarheid. Je kunt hun implementaties vinden in het GitHub-project dat aan het einde van dit artikel is gelinkt.

3. Het draait allemaal om persistentiecontext

Voordat we ingaan op het onderwerp van de levenscyclus van een entiteit, moeten we dit eerst begrijpen de persistentiecontext.

Simpel gezegd, de persistentie context zit tussen klantcode en gegevensopslag. Het is een verzamelplaats waar permanente gegevens worden geconverteerd naar entiteiten, klaar om te worden gelezen en gewijzigd door clientcode.

Theoretisch gezien is de persistentie context is een implementatie van het werkeenheidpatroon. Het houdt alle geladen gegevens bij, houdt wijzigingen van die gegevens bij en is verantwoordelijk om eventuele wijzigingen aan het einde van de zakelijke transactie uiteindelijk terug te synchroniseren naar de database.

JPA EntityManager en Hibernate's Sessie zijn een implementatie van de persistentie context concept. In dit artikel gebruiken we Hibernate Sessie te representeren persistentie context.

Hibernate entiteit levenscyclusstatus legt uit hoe de entiteit is gerelateerd aan een persistentie context, zoals we hierna zullen zien.

4. Beheerde entiteit

Een beheerde entiteit is een weergave van een databasetabelrij (hoewel die rij nog niet in de database hoeft te bestaan).

Dit wordt beheerd door de momenteel draaiende Sessie, en elke wijziging die erop wordt aangebracht, wordt bijgehouden en automatisch naar de database doorgegeven.

De Sessie laadt de entiteit uit de database of voegt een losgekoppelde entiteit opnieuw toe. We bespreken vrijstaande entiteiten in sectie 5.

Laten we wat code bekijken om opheldering te krijgen.

Onze voorbeeldtoepassing definieert één entiteit, het Voetballer klasse. Bij het opstarten initialiseren we de gegevensopslag met enkele voorbeeldgegevens:

+ ------------------- + ------- + | Naam | ID | + ------------------- + ------- + | Cristiano Ronaldo | 1 | | Lionel Messi | 2 | | Gianluigi Buffon | 3 | + ------------------- + ------- +

Laten we zeggen dat we de naam van Buffon willen veranderen om mee te beginnen - we willen zijn volledige naam invoeren Gianluigi Buffon in plaats van Gigi Buffon.

Ten eerste moeten we onze werkeenheid starten door een Sessie:

Sessiesessie = sessionFactory.openSession ();

In een serveromgeving kunnen we een Sessie naar onze code via een contextbewuste proxy. Het principe blijft hetzelfde: we hebben een Sessie om de zakelijke transactie van onze werkeenheid samen te vatten.

Vervolgens zullen we ons instrueren Sessie om de gegevens uit de permanente opslag te laden:

assertThat (getManagedEntities (sessie)). isEmpty (); Lijst met spelers = s.createQuery ("van FootballPlayer"). GetResultList (); assertThat (getManagedEntities (sessie)). size (). isEqualTo (3); 

Wanneer we voor het eerst een Sessie, is de permanente contextopslag leeg, zoals blijkt uit onze eerste beweren uitspraak.

Vervolgens voeren we een query uit die gegevens uit de database ophaalt, een entiteitsweergave van de gegevens maakt en uiteindelijk de entiteit retourneert die we kunnen gebruiken.

Intern is het Sessie houdt alle entiteiten bij die het laadt in de permanente contextopslag. In ons geval is de Sessie interne opslag bevat 3 entiteiten na de zoekopdracht.

Laten we nu de naam van Gigi veranderen:

Transactie transactie = session.getTransaction (); transactie.begin (); FootballPlayer gigiBuffon = players.stream () .filter (p -> p.getId () == 3) .findFirst () .get (); gigiBuffon.setName ("Gianluigi Buffon"); transactie.commit (); assertThat (getDirtyEntities ()). size (). isEqualTo (1); assertThat (getDirtyEntities (). get (0) .getName ()). isEqualTo ("Gianluigi Buffon");

4.1. Hoe werkt het?

Op afroep tot transactie plegen () of doorspoelen (), de Sessie zal er een vinden vuil entiteiten uit de trackinglijst en synchroniseer de staat met de database.

Merk op dat we geen enkele methode hoefden aan te roepen om een ​​melding te doen Sessie dat we iets in onze entiteit hebben gewijzigd - aangezien het een beheerde entiteit is, worden alle wijzigingen automatisch doorgevoerd in de database.

Een beheerde entiteit is altijd een permanente entiteit - het moet een database-ID hebben, ook al is de weergave van de databaserij nog niet gemaakt, d.w.z. de instructie INSERT wacht op het einde van de werkeenheid.

Zie het hoofdstuk over tijdelijke entiteiten hieronder.

5. Vrijstaande entiteit

EEN vrijstaande entiteit is gewoon een gewone entiteit POJO waarvan de identiteitswaarde overeenkomt met een databaserij. Het verschil met een beheerde entiteit is dat het door niemand meer gevolgd persistentie context.

Een entiteit kan loskomen als de Sessie gebruikt om te laden was het gesloten, of wanneer we bellen Session.evict (entiteit) of Session.clear ().

Laten we het in de code zien:

FootballPlayer cr7 = session.get (FootballPlayer.class, 1L); assertThat (getManagedEntities (sessie)). size (). isEqualTo (1); assertThat (getManagedEntities (sessie) .get (0) .getId ()). isEqualTo (cr7.getId ()); session.evict (cr7); assertThat (getManagedEntities (sessie)). size (). isEqualTo (0);

Onze persistentiecontext zal de wijzigingen in ontkoppelde entiteiten niet volgen:

cr7.setName ("CR7"); transactie.commit (); assertThat (getDirtyEntities ()). isEmpty ();

Session.merge (entiteit) /Session.update (entiteit) kan (her) voeg een sessie toe:

FootballPlayer messi = session.get (FootballPlayer.class, 2L); session.evict (messi); messi.setName ("Leo Messi"); transactie.commit (); assertThat (getDirtyEntities ()). isEmpty (); transactie = startTransaction (sessie); session.update (messi); transactie.commit (); assertThat (getDirtyEntities ()). size (). isEqualTo (1); assertThat (getDirtyEntities (). get (0) .getName ()). isEqualTo ("Leo Messi");

Ter referentie over beide Session.merge () en Session.update () kijk hier.

5.1. Het identiteitsveld is het enige dat telt

Laten we eens kijken naar de volgende logica:

FootballPlayer gigi = nieuwe FootballPlayer (); gigi.setId (3); gigi.setName ("Gigi the Legend"); session.update (gigi);

In het bovenstaande voorbeeld hebben we een entiteit op de gebruikelijke manier geïnstantieerd via de constructor. We hebben de velden gevuld met waarden en we hebben de identiteit ingesteld op 3, wat overeenkomt met de identiteit van permanente gegevens die bij Gigi Buffon horen. Roeping bijwerken() heeft precies hetzelfde effect alsof we de entiteit van een andere hebben geladen persistentie context.

In feite, Sessie maakt geen onderscheid waar een opnieuw gekoppelde entiteit vandaan komt.

Het is een vrij algemeen scenario in webtoepassingen om losstaande entiteiten te construeren op basis van HTML-formulierwaarden.

Voor zover Sessie betreft, een onthechte entiteit is gewoon een gewone entiteit waarvan de identiteitswaarde overeenkomt met persistente gegevens.

Houd er rekening mee dat het bovenstaande voorbeeld slechts een demo-doel dient. en we moeten precies weten wat we doen. Anders zouden we kunnen eindigen met null-waarden in onze entiteit als we de waarde gewoon instellen op het veld dat we willen bijwerken, en de rest onaangeroerd laten (dus in feite null).

6. Tijdelijke entiteit

Een voorbijgaande entiteit is gewoon een entiteit object dat geen vertegenwoordiging heeft in de permanente opslag en wordt door niemand beheerd Sessie.

Een typisch voorbeeld van een tijdelijke entiteit is het instantiëren van een nieuwe entiteit via zijn constructor.

Om een ​​voorbijgaande entiteit te maken aanhoudend, we moeten bellen Session.save (entiteit) of Session.saveOrUpdate (entiteit):

FootballPlayer neymar = nieuwe FootballPlayer (); neymar.setName ("Neymar"); session.save (neymar); assertThat (getManagedEntities (sessie)). size (). isEqualTo (1); assertThat (neymar.getId ()). isNotNull (); int count = queryCount ("selecteer count (*) van Football_Player where name =" Neymar ""); assertThat (count) .isEqualTo (0); transactie.commit (); count = queryCount ("selecteer count (*) van Football_Player where name =" Neymar ""); assertThat (count) .isEqualTo (1);

Zodra we executeren Session.save (entiteit), krijgt de entiteit een identiteitswaarde toegewezen en wordt deze beheerd door de Sessie. Het is echter mogelijk nog niet beschikbaar in de database, omdat de INSERT-bewerking mogelijk wordt uitgesteld tot het einde van de werkeenheid.

7. Verwijderde entiteit

Een entiteit heeft een verwijderde (verwijderde) status als Session.delete (entiteit) is gebeld, en de Sessie heeft de entiteit gemarkeerd voor verwijdering. Het DELETE-commando zelf kan aan het einde van de werkeenheid worden gegeven.

Laten we het eens zien in de volgende code:

session.delete (neymar); assertThat (getManagedEntities (sessie) .get (0) .getStatus ()). isEqualTo (Status.DELETED);

Merk echter op dat de entiteit in de permanente contextopslag blijft tot het einde van de werkeenheid.

8. Conclusie

Het concept van persistentie context staat centraal bij het begrijpen van de levenscyclus van Hibernate-entiteiten. We hebben de levenscyclus verduidelijkt door de codevoorbeelden te bekijken die elke status demonstreren.

Zoals gewoonlijk is de code die in dit artikel wordt gebruikt, te vinden op GitHub.