inițializarea leneșă, o problemă de hibernare

există o excepție populară care o mulțime de hibernare newbees întâlni. Pentru a preveni această excepție, trebuie să înțelegeți conceptul de inițializare leneșă.

1)când Hibernate citește date din Baza de date, datele sunt păstrate în sesiune. Puteți salva referințele la date – de exemplu în solicitarea HTTP. Odată ce tranzacția este comisă și sesiunea este închisă, nu puteți încărca alte date cu această sesiune.

în primul exemplu, am văzut că mierea are o colecție de albine. Dacă încărcăm o instanță de miere, Hibernate nu va încărca automat albinele. Există un motiv bun pentru acest comportament. Imaginați-vă că încărcați o companie și obțineți toate comenzile, detaliile comenzii și articolele. Practic încărcați cea mai mare parte a bazei de date doar prin încărcarea unui singur obiect companie. Acest lucru ar duce la o problemă de memorie. Prin urmare, Hibernate încarcă numai primul obiect și înlocuiește colecțiile altor obiecte printr-un proxy. Dacă accesați proxy-ul, Hibernate utilizează sesiunea curentă pentru a inițializa proxy-ul și a încărca intrările din Baza de date.

2)Imaginați-vă o aplicație cadru Struts. Dacă nu știți Struts: este un cadru pentru dezvoltarea aplicațiilor web. Când un utilizator solicită ceva, de exemplu, a trimis un formular pe un site web, se întâmplă următoarele:

  • servlet central se numește
  • servlet caută logica aplicației pentru cerere și apelează logica aplicației
  • logica aplicației deschide o sesiune, Salvează sau preia date
  • logica aplicației stochează datele preluate în cerere și închide sesiunea
  • controlul revine la servlet
  • servlet apelează un JSP pentru a reda dialogul
  • JSP utilizează datele din cerere

care este consecința 1) și 2)? Când te uiți prin procesul 2) puteți vedea că sesiunea este deja închisă, atunci când dialogul este redat. Logica aplicației dvs. a terminat procesarea. Dacă nu ați inițializat niciun obiect în timp ce sesiunea dvs. este deschisă, nu le veți putea afișa. Aruncati o privire pe diagrama următoare, ceea ce explică situațiile destul de bine. \ newline

când accesați un obiect neinițializat, veți primi o LazyInitializationException explicând că sesiunea este deja închisă.

images/c_architecture_sequence_diagram.jpg

când se poate întâmpla acest lucru? Am menționat că Hibernate poate mapa relațiile. Imaginați-vă un departament de clasă având un număr de echipe.

public class Department { private Integer id; private String name; private Set teams = new HashSet();

dacă doriți să afișați o listă de departamente și echipe în JSP, nu trebuie să preluați numai toate instanțele Departamentului, ci și toate instanțele echipelor care sunt asociate cu unul dintre departamentele pe care le recuperați.

v-am spus că în mod implicit toate relațiile sunt recuperate leneș. Aceasta înseamnă că atunci când preluați un departament, Hibernate nu va prelua echipele, ci va crea un proxy. Când accesați o echipă, proxy-ul utilizează sesiunea curentă pentru a încărca echipa din Baza de date. Un proxy poate prelua date numai atunci când sesiunea este deschisă.

având relații în maparea dvs. trebuie să vă asigurați că obiectul și obiectele conexe sunt inițializate atât timp cât sesiunea este deschisă.

există trei soluții la această problemă:

  • Define lazy = „false” în maparea dvs.
  • aduceți în mod explicit datele asociate în interogarea dvs.
  • folosiți un truc și amânați închiderea sesiunii la o dată ulterioară, când JSP-ul dvs. este deja redat.

prima soluție este periculoasă. Imaginați-vă o relație

ApplicationUser → KeyAccounter → Client → Societate → toți clienții companiei → toate comenzile clienților

Fiecare acces ar încărca baza de date completă. Fii foarte atent atunci când setați leneș la fals.

a doua soluție este simplă, dar are unele avertismente. Trucul se numește Open-Session-in-View și este explicat în Capitol sesiune deschisă în Vizualizaresecțiunea numită”durata de viață până când vizualizarea este redată (Open-Session-in-View)”.

a treia soluție inițializează datele înainte de închiderea sesiunii.

avem două opțiuni pentru inițializarea datelor.

abordarea a)

List honeys = session.createQuery("select h from Honey as h").list();for (Iterator iter = honeys.iterator(); iter.hasNext();) { Honey element = (Honey) iter.next(); log.debug(element); Hibernate.initialize(element.getBees());

abordarea b)

honeys = session.createQuery("select h from Honey as h left join fetch h.bees") .list()

dacă utilizați abordarea a) trebuie să apelați pentru a apela hibernare.inițializați pe fiecare proxy. Fiecare apel va genera o interogare.

abordarea b) generează o declarație de Asociere la stânga. Vom avea nevoie doar de o singură interogare.

luați în considerare utilizarea b) dacă interogați o mulțime de date.

trebuie să fiți conștienți de o retragere a acestei abordări. Stânga se alăture rezultate în intrări duble pentru factură atunci când există mai multe comenzi. Gândiți-vă la interogarea sql de bază, care duce la un rezultat ca

invoice 1, joined order line 1invoice 1, joined order line 2invoice 2, joined order line 1.....

Hibernate va adăuga, de asemenea, factura 1 de mai multe ori la lista de rezultate.

puteți utiliza următoarea abordare pentru a obține facturi unice (aruncați o privire în capitolul de interogare HQL și criterii pentru exemple detaliate):

session.createCriteria(Honey.class).setFetchMode("bees",FetchMode.JOIN) .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();session.createQuery("select h from Honey as h join fetch h.bees") .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();

Posted on

Lasă un răspuns

Adresa ta de email nu va fi publicată.