Objectstaten in de sessie van de slaapstand

1. Inleiding

Hibernate is een handig raamwerk voor het beheren van persistente gegevens, maar het kan soms lastig zijn om te begrijpen hoe het intern werkt.

In deze zelfstudie leren we objectstatussen en hoe u ertussen kunt schakelen. We zullen ook kijken naar de problemen die we kunnen tegenkomen met vrijstaande entiteiten en hoe deze kunnen worden opgelost.

2. Hibernate-sessie

De Sessie interface is de belangrijkste tool die wordt gebruikt om te communiceren met Hibernate. Het biedt een API waarmee we blijvende objecten kunnen maken, lezen, bijwerken en verwijderen. De sessie heeft een eenvoudige levenscyclus. We openen het, voeren enkele bewerkingen uit en sluiten het vervolgens.

Wanneer we de objecten opereren tijdens de sessie, raken ze daaraan gehecht sessie. De wijzigingen die we aanbrengen, worden gedetecteerd en opgeslagen bij het sluiten. Na het sluiten verbreekt Hibernate de verbindingen tussen de objecten en de sessie.

3. Objectstaten

In de context van Hibernate's Sessieobjecten kunnen zich in een van de drie mogelijke toestanden bevinden: van voorbijgaande aard, persistent of losgekoppeld.

3.1. Van voorbijgaande aard

Een object waaraan we geen enkele hebben gehecht sessie is in de voorbijgaande toestand. Omdat het nooit werd bewaard, heeft het geen enkele vertegenwoordiging in de database. Want nee sessie zich hiervan bewust is, wordt het niet automatisch opgeslagen.

Laten we een gebruikersobject maken met de constructor en bevestigen dat het niet wordt beheerd door de sessie:

Sessie sessie = openSession (); UserEntity userEntity = nieuwe UserEntity ("John"); assertThat (session.contains (userEntity)). isFalse ();

3.2. Aanhoudend

Een object dat we hebben geassocieerd met een sessie is in de aanhoudende staat. We hebben het opgeslagen of gelezen vanuit een persistentiecontext, dus het vertegenwoordigt een rij in de database.

Laten we een object maken en vervolgens de volharden methode om het persistent te maken:

Sessie sessie = openSession (); UserEntity userEntity = nieuwe UserEntity ("John"); session.persist (userEntity); assertThat (session.contains (userEntity)). isTrue ();

Als alternatief kunnen we de sparen methode. Het verschil is dat de volharden methode slaat gewoon een object op, en de sparen method zal bovendien zijn identifier genereren als dat nodig is.

3.3. Vrijstaand

Als we het sessie, alle objecten erin worden losgemaakt. Hoewel ze nog steeds rijen in de database vertegenwoordigen, worden ze door geen enkele sessie:

session.persist (userEntity); session.close (); assertThat (session.isOpen ()). isFalse (); assertThatThrownBy (() -> session.contains (userEntity));

Vervolgens leren we hoe we tijdelijke en ontkoppelde entiteiten kunnen opslaan.

4. Een entiteit opslaan en opnieuw koppelen

4.1. Een tijdelijke entiteit opslaan

Laten we een nieuwe entiteit maken en deze in de database opslaan. Wanneer we het object voor het eerst construeren, bevindt het zich in de voorbijgaande toestand.

Naar volharden onze nieuwe entiteit gebruiken we de volharden methode:

UserEntity userEntity = nieuwe UserEntity ("John"); session.persist (userEntity);

Nu gaan we een ander object maken met dezelfde ID als het eerste. Dit tweede object is van voorbijgaande aard omdat het nog niet door iemand wordt beheerd sessie, maar we kunnen het niet persistent maken met de volharden methode. Het is al vertegenwoordigd in de database, dus het is niet echt nieuw in de context van de persistentielaag.

In plaats daarvan, we zullen de samenvoegen methode om de database bij te werken en het object persistent te maken:

UserEntity onceAgainJohn = nieuwe UserEntity ("John"); session.merge (onceAgainJohn);

4.2. Een vrijstaande entiteit opslaan

Als we het vorige sessie, onze objecten zullen in een vrijstaande staat verkeren. Net als in het vorige voorbeeld worden ze weergegeven in de database, maar worden ze momenteel niet beheerd door een sessie. We kunnen ze weer persistent maken met behulp van de samenvoegen methode:

UserEntity userEntity = nieuwe UserEntity ("John"); session.persist (userEntity); session.close (); session.merge (userEntity);

5. Geneste entiteiten

Het wordt ingewikkelder als we geneste entiteiten beschouwen. Laten we zeggen dat onze gebruikersentiteit ook informatie over zijn manager zal opslaan:

openbare klasse UserEntity {@Id private String-naam; @ManyToOne privé UserEntity-manager; }

Wanneer we deze entiteit opslaan, moeten we niet alleen nadenken over de staat van de entiteit zelf, maar ook over de staat van de geneste entiteit. Laten we een permanente gebruikersentiteit maken en vervolgens de manager instellen:

UserEntity userEntity = nieuwe UserEntity ("John"); session.persist (userEntity); UserEntity manager = nieuwe UserEntity ("Adam"); userEntity.setManager (manager);

Als we het nu proberen bij te werken, krijgen we een uitzondering:

assertThatThrownBy (() -> {session.saveOrUpdate (userEntity); transaction.commit ();});
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object verwijst naar een niet-opgeslagen tijdelijke instantie - sla de tijdelijke instantie op voordat u deze doorspoelt: com.baeldung.states.UserEntity.manager -> com.baeldung.states.UserEntity 

Dat gebeurt omdat Hibernate niet weet wat te doen met de tijdelijke geneste entiteit.

5.1. Aanhoudende geneste entiteiten

Een manier om dit probleem op te lossen, is door geneste entiteiten expliciet te behouden:

UserEntity manager = nieuwe UserEntity ("Adam"); session.persist (manager); userEntity.setManager (manager);

Vervolgens, na het uitvoeren van de transactie, kunnen we de correct opgeslagen entiteit ophalen:

transactie.commit (); session.close (); Sessie otherSession = openSession (); UserEntity opgeslagenUser = otherSession.get (UserEntity.class, "John"); assertThat (savedUser.getManager (). getName ()). isEqualTo ("Adam");

5.2. Trapsgewijze operaties

Voorbijgaande geneste entiteiten kunnen automatisch worden gehandhaafd als we de cascade eigenschap correct in de entiteitsklasse:

@ManyToOne (cascade = CascadeType.PERSIST) privé UserEntity-manager;

Wanneer we het object voortzetten, wordt die bewerking gecascadeerd naar alle geneste entiteiten:

UserEntityWithCascade userEntity = nieuwe UserEntityWithCascade ("John"); session.persist (userEntity); UserEntityWithCascade manager = nieuwe UserEntityWithCascade ("Adam"); userEntity.setManager (manager); // tijdelijke manager toevoegen aan permanente gebruikerssessie. saveOrUpdate (userEntity); transactie.commit (); session.close (); Sessie otherSession = openSession (); UserEntityWithCascade opgeslagenUser = otherSession.get (UserEntityWithCascade.class, "John"); assertThat (savedUser.getManager (). getName ()). isEqualTo ("Adam");

6. Samenvatting

In deze tutorial hebben we nader bekeken hoe de Hibernate Sessie werkt met betrekking tot de objecttoestand. Vervolgens hebben we enkele problemen geïnspecteerd die het kan veroorzaken en hoe we deze kunnen oplossen.

Zoals altijd is de broncode beschikbaar op GitHub.