Gør indsigelse mod stater i dvaleens session

1. Introduktion

Dvaletilstand er en praktisk ramme til styring af vedvarende data, men det kan til tider være vanskeligt at forstå, hvordan det fungerer internt.

I denne vejledning lærer vi om objekttilstande og hvordan man bevæger sig mellem dem. Vi ser også på de problemer, vi kan støde på med løsrevne enheder, og hvordan vi løser dem.

2. Dvale-session

Det Session interface er det vigtigste værktøj, der bruges til at kommunikere med dvale. Det giver en API, der giver os mulighed for at oprette, læse, opdatere og slette vedvarende objekter. Det session har en simpel livscyklus. Vi åbner det, udfører nogle operationer og lukker det derefter.

Når vi betjener objekterne under session, de bliver knyttet til det session. De ændringer, vi foretager, opdages og gemmes, når de lukkes. Efter lukning bryder dvale forbindelserne mellem objekterne og sessionen.

3. Gør indsigelse mod stater

I sammenhæng med dvale Session, objekter kan være i en af ​​tre mulige tilstande: forbigående, vedholdende eller løsrevet.

3.1. Forbigående

Et objekt, vi ikke har knyttet til nogen session er i forbigående tilstand. Da det aldrig var vedvarende, har det ingen repræsentation i databasen. Fordi Nej session er opmærksom på det, gemmes det ikke automatisk.

Lad os oprette et brugerobjekt med konstruktøren og bekræfte, at det ikke styres af sessionen:

Session session = openSession (); UserEntity userEntity = ny UserEntity ("John"); assertThat (session.contains (userEntity)). isFalse ();

3.2. Vedholdende

Et objekt, som vi har tilknyttet et session er i vedvarende tilstand. Vi gemte det enten eller læste det fra en persistens-kontekst, så det repræsenterer en række i databasen.

Lad os oprette et objekt og derefter bruge vedvarer metode til at gøre det vedvarende:

Session session = openSession (); UserEntity userEntity = ny UserEntity ("John"); session.persist (userEntity); assertThat (session.contains (userEntity)). isTrue ();

Alternativt kan vi bruge Gemme metode. Forskellen er, at vedvarer metoden gemmer bare et objekt, og Gemme Metoden genererer desuden sin identifikator, hvis det er nødvendigt.

3.3. Fritliggende

Når vi lukker session, bliver alle genstande inde i den løsrevet. Selvom de stadig repræsenterer rækker i databasen, styres de ikke længere af nogen session:

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

Derefter lærer vi, hvordan man gemmer forbigående og løsrevne enheder.

4. Gemme og tilslutte en enhed igen

4.1. Gemme en forbigående enhed

Lad os oprette en ny enhed og gemme den i databasen. Når vi først konstruerer objektet, vil det være i forbigående tilstand.

Til vedvarer vores nye enhed, vi bruger vedvarer metode:

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

Nu opretter vi et andet objekt med samme identifikator som det første. Dette andet objekt er forbigående, fordi det endnu ikke styres af nogen session, men vi kan ikke gøre det vedholdende ved hjælp af vedvarer metode. Det er allerede repræsenteret i databasen, så det er ikke rigtig nyt i sammenhæng med persistenslaget.

I stedet, vi bruger fusionere metode til at opdatere databasen og gøre objektet vedvarende:

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

4.2. Gemme en løsrevet enhed

Hvis vi lukker det forrige session, vil vores objekter være i en løsrevet tilstand. På samme måde som det foregående eksempel er de repræsenteret i databasen, men de administreres i øjeblikket ikke af nogen session. Vi kan gøre dem vedholdende igen ved hjælp af fusionere metode:

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

5. Indlejrede enheder

Ting bliver mere komplicerede, når vi betragter indlejrede enheder. Lad os sige, at vores brugerenhed også gemmer oplysninger om sin manager:

offentlig klasse UserEntity {@Id privat strengnavn; @ManyToOne privat UserEntity manager; }

Når vi gemmer denne enhed, skal vi ikke kun tænke på selve enhedens tilstand, men også på tilstanden for den indlejrede enhed. Lad os oprette en vedvarende brugerenhed og derefter indstille dens manager:

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

Hvis vi prøver at opdatere det nu, får vi en undtagelse:

assertThatThrownBy (() -> {session.saveOrUpdate (userEntity); transaction.commit ();});
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: objektet henviser til en ikke-gemt forbigående forekomst - gem den forbigående forekomst inden skylning: com.baeldung.states.UserEntity.manager -> com.baeldung.states.UserEntity 

Det sker, fordi dvale ikke ved, hvad de skal gøre med den forbigående indlejrede enhed.

5.1. Vedvarende indlejrede enheder

En måde at løse dette problem på er eksplicit at fastholde indlejrede enheder:

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

Derefter, efter at have begået transaktionen, kan vi hente den korrekt gemte enhed:

transaktion.forpligtelse (); session.close (); Session otherSession = openSession (); UserEntity savedUser = otherSession.get (UserEntity.class, "John"); assertThat (savedUser.getManager (). getName ()). isEqualTo ("Adam");

5.2. Cascading Operations

Forbigående indlejrede enheder kan vedvares automatisk, hvis vi konfigurerer forholdet kaskade ejendom korrekt i enhedsklassen:

@ManyToOne (cascade = CascadeType.PERSIST) privat UserEntity manager;

Når vi fortsætter med objektet, vil denne operation blive kaskaderet for alle indlejrede enheder:

UserEntityWithCascade userEntity = ny UserEntityWithCascade ("John"); session.persist (userEntity); UserEntityWithCascade manager = ny UserEntityWithCascade ("Adam"); userEntity.setManager (manager); // tilføj transient manager til vedvarende brugersession.saveOrUpdate (userEntity); transaktion.forpligtelse (); session.close (); Session otherSession = openSession (); UserEntityWithCascade savedUser = otherSession.get (UserEntityWithCascade.class, "John"); assertThat (savedUser.getManager (). getName ()). isEqualTo ("Adam");

6. Resume

I denne vejledning kiggede vi nærmere på, hvordan dvale Session arbejder med hensyn til objekttilstand. Vi inspicerede derefter nogle problemer, det kan skabe, og hvordan vi løser dem.

Som altid er kildekoden tilgængelig på GitHub.