Dvalemodus kunne ikke initialisere proxy - ingen økt

1. Oversikt

Når vi arbeider med dvalemodus, har vi kanskje fått en feil som sier: org.hibernate.LazyInitializationException: kunne ikke initialisere proxy - ingen økt.

I denne raske opplæringen vil vi se nærmere på årsaken til feilen og lære hvordan du kan unngå den.

2 Forstå feilen

Tilgang til et dovet lastet objekt utenfor konteksten til en åpen dvale-økt vil resultere i dette unntaket.

Det er viktig å forstå hva er økt, Lat initialisering,og Proxy-objekt og hvordan de kommer sammen i Dvalemodus rammeverk.

  • Økt er en utholdenhetskontekst som representerer en samtale mellom et program og databasen
  • Lazy Loading betyr at objektet ikke blir lastet til Økt kontekst til den er tilgjengelig i kode.
  • Dvalemodus skaper en dynamikk Proxy-objekt underklasse som bare treffer databasen når vi først bruker objektet.

Denne feilen betyr at vi prøver å hente et dovet lastet objekt fra databasen ved hjelp av et proxy-objekt, men dvalemodus-økten er allerede lukket.

3. Eksempel for LazyInitializationException

La oss se unntaket i et konkret scenario.

Vi ønsker å lage en enkel Bruker objekt med tilhørende roller. La oss bruke JUnit til å demonstrere LazyInitializationException feil.

3.1. Hibernate Utility Class

La oss først definere en HibernateUtil klasse for å lage en SessionFactory med konfigurasjon.

Vi bruker minnet HSQLDB database.

3.2. Enheter

Her er vår Bruker enhet:

@Entity @Table (name = "user") offentlig klasse bruker {@Id @GeneratedValue (strategi = GenerationType.IDENTITY) @Column (name = "id") privat int id; @Column (name = "first_name") privat streng fornavn; @Column (name = "last_name") private streng etternavn; @OneToMany private Set roller; } 

Og det tilhørende Roll enhet:

@Entity @Table (name = "role") offentlig klasse rolle {@Id @GeneratedValue (strategi = GenerationType.IDENTITY) @Column (name = "id") privat int id; @Column (name = "role_name") private String roleName; }

Som vi kan se, er det en en-til-mange sammenheng mellom Bruker og Roll.

3.3. Opprette bruker med roller

La oss deretter lage to Roll gjenstander:

Rolleadministrator = ny rolle ("Admin"); Rolle dba = ny rolle ("DBA");

Deretter lager vi en Bruker med rollene:

Brukerbruker = ny bruker ("Bob", "Smith"); user.addRole (admin); user.addRole (dba);

Til slutt kan vi åpne en økt og vedvare objektene:

Sessionsøkt = sessionFactory.openSession (); session.beginTransaction (); user.getRoles (). forEach (rolle -> session.save (rolle)); session.save (bruker); session.getTransaction (). commit (); session.close ();

3.4. Henter roller

I det første scenariet ser vi hvordan du henter brukerroller på en riktig måte:

@Test offentlig ugyldig nårAccessUserRolesInsideSession_thenSuccess () {User detachedUser = createUserWithRoles (); Sessionsøkt = sessionFactory.openSession (); session.beginTransaction (); Bruker persistentUser = session.find (User.class, detachedUser.getId ()); Assert.assertEquals (2, persistentUser.getRoles (). Størrelse ()); session.getTransaction (). commit (); session.close (); }

Her får vi tilgang til objektet inne i økten, derfor er det ingen feil.

3.5. Henter rollefeil

I det andre scenariet vil vi kalle a getRoles metode utenfor økten:

@Test offentlig ugyldig nårAccessUserRolesOutsideSession_thenThrownException () {User detachedUser = createUserWithRoles (); Sessionsøkt = sessionFactory.openSession (); session.beginTransaction (); Bruker persistentUser = session.find (User.class, detachedUser.getId ()); session.getTransaction (). commit (); session.close (); throw.expect (LazyInitializationException.class); System.out.println (persistentUser.getRoles (). Størrelse ()); }

I så fall prøver vi å få tilgang til rollene etter at økten ble avsluttet, og som et resultat kaster koden a LazyInitializationException.

4. Hvordan unngå feilen

La oss ta en titt på fire forskjellige løsninger for å overvinne feilen.

4.1. Åpne økt i øvre lag

Den beste fremgangsmåten er å åpne en økt i utholdenhetslaget, for eksempel ved å bruke DAO-mønsteret.

Vi kan åpne økten i de øvre lagene for å få tilgang til de tilknyttede objektene på en trygg måte. For eksempel kan vi åpne økten i Utsikt lag.

Som et resultat ser vi en økning i responstid, noe som vil påvirke ytelsen til applikasjonen.

Denne løsningen er et antimønster når det gjelder Separation of Concerns-prinsippet. I tillegg kan det føre til brudd på dataintegriteten og langvarige transaksjoner.

4.2. Slå på enable_lazy_load_no_trans Eiendom

Denne dvalemodus-egenskapen brukes til å erklære en global policy for henting av dovne objekter.

Som standard er denne egenskapen falsk. Å slå den på betyr at hver tilgang til en tilknyttet lat-lastet enhet blir pakket inn i en ny økt som kjører i en ny transaksjon:

Bruk av denne egenskapen for å unngå LazyInitializationException feil anbefales ikke siden det vil redusere ytelsen til applikasjonen vår. Dette er fordi vi ende opp med et n + 1-problem. Enkelt sagt, det betyr en VELG for Bruker og N tilleggsvalg for å hente rollene til hver bruker.

Denne tilnærmingen er ikke effektiv og betraktes også som et antimønster.

4.3. Ved hjelp av FetchType.EAGER Strategi

Vi kan bruke denne strategien sammen med en @OneToMany kommentar, for eksempel:

@OneToMany (fetch = FetchType.EAGER) @JoinColumn (name = "user_id") private Still roller;

Dette er en slags kompromittert løsning for en bestemt bruk når vi trenger å hente den tilhørende samlingen for de fleste av våre brukssaker.

Så det er mye lettere å erklære IVRIG hentetype i stedet for eksplisitt å hente samlingen for de fleste av de forskjellige forretningsstrømmene.

4.4. Bruker Join Fetching

Vi kan bruke en BLI MED FETCH direktivet i JPQL for å hente den tilknyttede samlingen på forespørsel, for eksempel:

VELG u FRA bruker u BLI MED FETCH u.roles

Eller vi kan bruke Hibernate Criteria API:

Kriteriekriterier = session.createCriteria (User.class); criteria.setFetchMode ("roller", FetchMode.EAGER);

Her spesifiserer vi den tilknyttede samlingen som skal hentes fra databasen sammen med Bruker objekt på samme rundtur. Bruk av dette spørsmålet forbedrer effektiviteten til iterasjon siden det eliminerer behovet for å hente de tilknyttede objektene separat.

Dette er den mest effektive og finkornede løsningen for å unngå LazyInitializationException feil.

5. Konklusjon

I denne artikkelen så vi hvordan vi skal håndtere org.hibernate.LazyInitializationException: kunne ikke initialisere proxy - ingen økt feil.

Vi utforsket forskjellige tilnærminger sammen med ytelsesproblemer. Det er viktig å bruke en enkel og effektiv løsning for å unngå å påvirke ytelsen.

Til slutt så vi hvordan tilnærmingen til å hente sammen er en god måte å unngå feilen.

Som alltid er koden tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found