Che cos'è il caricamento lento in Hibernate?


Risposte:


268

Supponi di avere un genitore e che quel genitore abbia una collezione di figli. L'ibernazione ora può "caricare lentamente" i bambini, il che significa che in realtà non carica tutti i bambini durante il caricamento del genitore. Invece, li carica quando richiesto per farlo. Puoi richiederlo esplicitamente o, e questo è molto più comune, l'ibernazione li caricherà automaticamente quando tenti di accedere a un bambino.

Il caricamento lento può aiutare a migliorare significativamente le prestazioni poiché spesso non avrai bisogno dei bambini e quindi non verranno caricati.

Attenzione anche al problema n + 1. L'ibernazione non caricherà effettivamente tutti i bambini quando accedi alla raccolta. Invece, caricherà ogni bambino singolarmente. Durante l'iterazione della raccolta, ciò provoca una query per ogni bambino. Per evitare ciò, puoi ingannare il caricamento simultaneo di tutti i bambini, ad esempio chiamando parent.getChildren (). Size ().


5
In alternativa, utilizzare Hibernate.initialize (parent.getChildren ())
HakunaMatata,

18
L'affermazione "quando accedi alla raccolta ... caricherà ogni bambino individualmente" è in realtà completamente inaccurata. In realtà è esattamente il contrario. Qualsiasi dereference di parent.getChildren () farà in modo che Hibernate carichi tutti i figli della raccolta in una query db. A meno che tu non abbia usato il suggerimento di caricamento pigro "extra pigro" molto speciale. O a meno che non si memorizzi nella cache la raccolta nella cache di secondo livello e anche i figli associati non vengano memorizzati nella cache.
Steve Ebersole,

Oh, Stack Overflow - la migliore risposta si trova in fondo alla pagina ;-)
Piotrek Hryciuk

76

"Caricamento lento" significa che un'entità verrà caricata solo quando si accede effettivamente all'entità per la prima volta.

Lo schema è così:

public Entity getEntity() {
    if (entity == null) {
        entity = loadEntity();
    }
    return entity;
}

Ciò consente di risparmiare in anticipo il costo del precaricamento / precompilazione di tutte le entità in un set di dati di grandi dimensioni, mentre in realtà non è necessario averle tutte .

In Hibernate, è possibile configurare per caricare pigramente una raccolta di entità figlio. Il caricamento pigro effettivo viene quindi eseguito all'interno dei metodi di PersistentSetcui Hibernate utilizza "under the hoods" per assegnare la raccolta di entità come Set.

Per esempio

public class Parent {
    private Set<Child> children;

    public Set<Child> getChildren() {
        return children;
    }
}

.

public void doSomething() {
    Set<Child> children = parent.getChildren(); // Still contains nothing.

    // Whenever you call one of the following (indirectly), 
    // Hibernate will start to actually load and fill the set.
    children.size();
    children.iterator();
}

25

Martin Fowler definisce il modello Lazy Load in Patterns of Enterprise Application Architecture come tale:

Un oggetto che non contiene tutti i dati necessari ma che sa come ottenerli.

Pertanto, quando si carica un determinato oggetto, l'idea è di non caricare con impazienza gli oggetti correlati che non è possibile utilizzare immediatamente per risparmiare sui relativi costi di prestazione. Al contrario, gli oggetti correlati verranno caricati solo quando utilizzati.

Questo non è un modello specifico per l'accesso ai dati e Hibernate, ma è particolarmente utile in tali campi e Hibernate supporta il caricamento pigro di associazioni uno-a-molti e associazioni a punto singolo (uno a uno e molti a uno) a determinate condizioni. L'interazione lenta è discussa in maggior dettaglio nel capitolo 19 della documentazione di riferimento di Hibernate 3.0.


15

Il caricamento lento predefinito è vero. Il caricamento lento indica che quando viene eseguita la query di selezione non verrà raggiunto il database. Aspetterà la funzione getter, ad esempio quando richiesto, recupererà dalla base di dati. per esempio: sei un genitore che ha un figlio con molti giocattoli. Ma il problema attuale è ogni volta che lo chiami (supponiamo che tu abbia un ragazzo), viene anche da te con tutti i suoi giocattoli. Ora questo è un problema poiché non vuoi che porti sempre con sé i suoi giocattoli. Quindi, essendo il genitore razionale, vai avanti e definisci i giocattoli del bambino come LAZY. Ora, ogni volta che lo chiami, viene da te senza i suoi giocattoli.


11

Il recupero lento decide se caricare oggetti figlio durante il caricamento dell'oggetto principale. È necessario eseguire questa impostazione rispettivo file di mapping di ibernazione della classe genitore. Lazy = true(significa non caricare figlio) Per impostazione predefinita, il caricamento lazy degli oggetti figlio è vero.

Ciò getChild()garantisce che gli oggetti figlio non vengano caricati a meno che non vengano esplicitamente richiamati nell'applicazione chiamando il metodo su parent. In questo caso l'ibernazione emette una nuova chiamata al database per caricare il figlio quando getChild()viene effettivamente chiamato sull'oggetto Parent.

Ma in alcuni casi è necessario caricare gli oggetti figlio quando viene caricato il genitore. Basta fare lazy = false e l'ibernazione caricherà il figlio quando il genitore viene caricato dal database.

Esempio: se hai una TABELLA? DIPENDENTE mappato sull'oggetto Employee e contiene un set di oggetti Address. Classe principale: classe dipendente, classe figlio: classe indirizzo

public class Employee { 
private Set address = new HashSet(); // contains set of child Address objects 
public Set getAddress () { 
return address; 
} 
public void setAddresss(Set address) { 
this. address = address; 
} 
} 

Nel file Employee.hbm.xml

<set name="address" inverse="true" cascade="delete" lazy="false"> 
<key column="a_id" /> 
<one-to-many class="beans Address"/> 
</set> 

Nella configurazione sopra. Se lazy="false": - quando si carica l'oggetto Employee, quel tempo viene anche caricato l'indirizzo dell'oggetto figlio e impostato sul metodo setAddresss (). Se si chiama employee.getAdress (), vengono restituiti i dati caricati. Nessuna nuova chiamata al database.

Se lazy="true": - Questa è la configurazione predefinita. Se non lo fai, allora iberna considera pigro = vero. quando si carica l'oggetto Employee in quel momento, l'oggetto secondario Adress non viene caricato. È necessaria una chiamata extra alla base dati per ottenere gli oggetti indirizzo. Se si chiama, employee.getAdress()allora quella query del database si attiva e restituisce risultati. Nuova chiamata al database.


Dipendente e indirizzo non hanno relazioni genitore-figlio in questo scenario. È una relazione "has-a" !
Ram

Questa è aggregazione non eredità.
Rishi,

11

Nella lingua dei laici, è come se stessi preparando una torta e avrai bisogno di 5-10 ingredienti dal frigorifero. Hai due opzioni, prendi tutti gli ingredienti dal frigorifero e mettili sulla piattaforma della tua cucina, oppure porta l'oggetto che desideri quando ne hai bisogno.

Allo stesso modo, nel caricamento desideroso, prendi tutte le informazioni sul fagiolo e le sue classi correlate (non una relazione figlio o è-ma ma ha una relazione, cioè una torta ha farina, ha latte, ha crema ecc.) E, in caso di caricamento pigro, prima porti solo il suo identificatore e i valori che provengono dalla stessa tabella (ingredienti necessari che prima ti serviranno nella tua ciotola in caso di torta). Tutte le informazioni che provengono da altre tabelle verranno recuperate come e quando richiesto / utilizzato.


8

Caricamento in corso? Bene, significa semplicemente che i record figlio non vengono recuperati immediatamente, ma automaticamente non appena si tenta di accedervi.


4

Il caricamento lento consente di rinviare il recupero dell'associazione o di avere un migliore controllo sulla strategia di recupero.

Quando si utilizza il caricamento EAGER, si definisce un piano di recupero globale che non può essere sovrascritto al momento della query, il che significa che si è limitati a una decisione presa durante la progettazione del modello di entità. Il recupero EAGER è un odore di codice , poiché la strategia di recupero è una politica del tempo di query e potrebbe differire da un caso d'uso aziendale a un altro.

La strategia di recupero è un aspetto molto importante, poiché un recupero eccessivo di EAGER può causare seri problemi di prestazioni.


3

L'impostazione Lazy decide se caricare oggetti figlio durante il caricamento dell'oggetto Parent. È necessario eseguire questa impostazione rispettivo file di mapping ibernazione della classe parent.Lazy = true (significa non caricare figlio) Per impostazione predefinita, il caricamento pigro degli oggetti figlio è vero . Questo assicura che gli oggetti figlio non vengano caricati a meno che non vengano esplicitamente richiamati nell'applicazione chiamando il metodo getChild () su parent.In questo caso l'ibernazione genera una nuova chiamata al database per caricare il figlio quando getChild () viene effettivamente chiamato sul padre object.Ma in alcuni casi è necessario caricare gli oggetti figlio quando viene caricato il genitore. Basta rendere lazy = false e l'ibernazione caricherà il figlio quando il genitore viene caricato dal database. Exampleslazy = true (impostazione predefinita) L'indirizzo figlio della classe User può essere reso pigro se non richiesto frequentemente.


2

Il caricamento lento è un modello di progettazione comunemente utilizzato nella programmazione per computer per rinviare l'inizializzazione di un oggetto fino al punto in cui è necessario. Può contribuire all'efficienza del funzionamento del programma se utilizzato correttamente e in modo appropriato

Wikipedia

Link di Lazy Loading da hibernate.org


1

Bene, significa semplicemente caricare i dati di cui hai bisogno attualmente invece di caricare un sacco di dati contemporaneamente che non utilizzerai ora. In questo modo il tempo di caricamento dell'applicazione è più veloce del solito.


0

Hiberante supporta la funzione di inizializzazione lazy per entità e raccolte. Il motore di ibernazione carica solo quegli oggetti per i quali stiamo eseguendo la query e non altri enti o raccolte.

lazy = "false" per impostazione predefinita caricamento menzione di inizializzazione per l'unico figlio è lazy.in caso di true che è il genitore che sta caricando non supporta figlio


0

L'impostazione Lazy decide se caricare oggetti figlio durante il caricamento dell'oggetto Parent. È necessario eseguire questa impostazione rispettivo file di mapping ibernazione della classe parent.Lazy = true (significa non caricare figlio) Per impostazione predefinita, il caricamento pigro degli oggetti figlio è vero .


0

Sorprendentemente, nessuna delle risposte parla di come viene raggiunto dal letargo dietro gli schermi.

Il caricamento lento è un modello di progettazione che viene effettivamente utilizzato in ibernazione per motivi di prestazioni che prevede le seguenti tecniche.


1. Strumentazione codice byte :

Migliora la definizione della classe di base con hook di ibernazione per intercettare tutte le chiamate a quell'oggetto entità.

Fatto in fase di compilazione o in esecuzione [caricamento]

1.1 Tempo di compilazione

  • Operazione post compilazione

  • Principalmente da plugin di maven / ant

1.2 Tempo di esecuzione

  • Se non viene eseguita alcuna strumentazione in fase di compilazione, questa viene creata in fase di esecuzione utilizzando librerie come javassist

2. Proxy

L'oggetto entità restituito da Hibernate è proxy del tipo reale.

Vedi anche: Javassist. Qual è l'idea principale e dove viene utilizzato?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.