Lat initialisering, ett viloläge problem

det finns ett populärt undantag som många Hibernate newbees möter. För att förhindra detta undantag måste du förstå begreppet Lat initialisering.

1)när viloläge läser data från databasen hålls data i sessionen. Du kan spara referenser till data – till exempel i din HTTP-begäran. När transaktionen har begåtts och sessionen är stängd kan du inte ladda ytterligare data med den här sessionen.

i det första exemplet har vi sett att honung har en samling bi. Om vi laddar en Honungsinstans kommer viloläge inte att ladda bina automatiskt. Det finns goda skäl till detta beteende. Tänk dig att du laddar ett företag och får alla beställningar, orderdetaljer och artiklar. I grund och botten laddar du det mesta av din Databas bara genom att ladda ett enda företagsobjekt. Detta skulle resultera i ett minnesproblem. Därför laddar Hibernate bara det första objektet och ersätter samlingar av andra objekt med en proxy. Om du öppnar proxyn använder Hibernate den aktuella sessionen för att initiera proxyn och ladda posterna från databasen.

2)Föreställ dig en Struts framework-applikation. Om du inte känner till Struts: det är ett ramverk för att utveckla webbapplikationer. När en användare begär något, t. ex. han har skickat in ett formulär på en webbplats, händer följande:

  • central servlet heter
  • servlet letar upp applikationslogik för begäran och anropar applikationslogiken
  • applikationslogik öppnar en session, sparar eller hämtar data
  • applikationslogik lagrar hämtad data i begäran och stänger sessionen
  • kontroll återgår till servlet
  • servlet anropar en JSP för att göra dialogrutan
  • JSP använder data i begäran

vad är konsekvensen av 1) och 2)? När du tittar igenom processen 2) kan du se att sessionen redan är stängd när dialogen återges. Din applikationslogik har avslutat behandlingen. Om du inte har initierat några objekt medan sessionen är öppen kommer du inte att kunna visa dem. Ta en titt på följande diagram, vilket förklarar situationerna ganska bra. \newline

när du öppnar ett icke initialiserat objekt får du en LazyInitializationException som förklarar att sessionen redan är stängd.

images/c_architecture_sequence_diagram.jpg

När kan detta hända? Jag har nämnt att viloläge kan kartlägga relationer. Föreställ dig en klassavdelning med ett antal lag.

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

om du vill mata ut en lista över avdelningar och team i din JSP måste du inte bara hämta alla instanser av avdelningen utan också alla instanser av lag som är associerade med en av de avdelningar du hämtar.

jag sa till dig att alla relationer som standard hämtas lata. Det betyder att när du hämtar en avdelning kommer Hibernate inte att hämta lagen utan skapa en proxy. När du öppnar ett team använder proxyn den aktuella sessionen för att ladda teamet från databasen. En proxy kan bara hämta data när sessionen är öppen.

att ha relationer i din mappning måste du se till att objektet och relaterade objekt initieras så länge sessionen är öppen.

det finns tre lösningar på detta problem:

  • definiera lazy=”false” i din mappning
  • hämta uttryckligen tillhörande data i din fråga
  • Använd ett trick och skjut upp slutet av sessionen till en senare tidpunkt när din JSP redan har renderats.

den första lösningen är farlig. Tänk dig en relation som

ApplicationUser → KeyAccounter → Kund → Företaget → alla kunder för företaget → alla beställningar av kunder

Varje tillgång skulle ladda den kompletta databasen. Var mycket försiktig när du sätter Lat till falskt.

den andra lösningen är enkel men har några varningar. Tricket heter Open-Session-in-View och förklaras i kapitel Open Session in Viewsektionen heter ”livstid tills vyn återges (Open-Session-in-View)”.

den tredje lösningen initierar data innan sessionen avslutas.

vi har två alternativ för att initiera data.

tillvägagångssätt 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());

tillvägagångssätt b)

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

om du använder tillvägagångssätt a) måste du ringa för att ringa viloläge.initiera på varje proxy. Varje samtal genererar en fråga.

tillvägagångssätt b) genererar ett left join-uttalande. Vi behöver bara en fråga.

överväg att använda b) om du frågar mycket data.

du måste vara medveten om oavgjort baksidan av detta tillvägagångssätt. Left join resulterar i dubbla poster för faktura när det finns flera beställningar. Tänk på den underliggande sql-frågan, vilket leder till ett resultat som

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

Hibernate kommer också att lägga till fakturan 1 flera gånger i resultatlistan.

du kan använda följande tillvägagångssätt för att få unika fakturor (ta en titt i kapitlet HQL och kriterier för detaljerade exempel):

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

Lämna ett svar

Din e-postadress kommer inte publiceras.