Qu'est-ce que le chargement différé dans Hibernate?

178

Qu'est-ce que le chargement différé en Java? Je ne comprends pas le processus. Quelqu'un peut-il m'aider à comprendre le processus de chargement paresseux?

bascule
la source

Réponses:

268

Disons que vous avez un parent et que ce parent a une collection d'enfants. Hibernate peut maintenant "charger paresseusement" les enfants, ce qui signifie qu'il ne charge pas réellement tous les enfants lors du chargement du parent. Au lieu de cela, il les charge à la demande de le faire. Vous pouvez demander cela explicitement ou, et c'est beaucoup plus courant, hibernate les chargera automatiquement lorsque vous essayez d'accéder à un enfant.

Le chargement différé peut aider à améliorer les performances de manière significative car souvent vous n'aurez pas besoin des enfants et donc ils ne seront pas chargés.

Méfiez-vous également du problème n + 1. Hibernate ne chargera pas réellement tous les enfants lorsque vous accédez à la collection. Au lieu de cela, il chargera chaque enfant individuellement. Lors de l'itération sur la collection, cela provoque une requête pour chaque enfant. Pour éviter cela, vous pouvez tromper hibernate en chargeant tous les enfants simultanément, par exemple en appelant parent.getChildren (). Size ().

Thomas Lötzer
la source
5
Alternativement Hibernate.initialize (parent.getChildren ()) doit être utilisé
HakunaMatata
18
La déclaration "lorsque vous accédez à la collection ... il chargera chaque enfant individuellement" est en fait complètement inexacte. C'est en fait exactement le contraire. Toute déréférence de parent.getChildren () obligera Hibernate à charger tous les enfants de la collection dans une requête db. Sauf si vous avez utilisé l'indication très spéciale de chargement paresseux "extra paresseux". Ou à moins que vous ne mettiez en cache la collection dans le cache de deuxième niveau et que les enfants associés ne soient pas également mis en cache.
Steve Ebersole
Oh, Stack Overflow - meilleure réponse à trouver en bas de page ;-)
Piotrek Hryciuk
76

"Chargement différé" signifie qu'une entité ne sera chargée que lorsque vous accéderez réellement à l'entité pour la première fois.

Le modèle est comme ceci:

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

Cela permet d'économiser le coût de préchargement / préremplissage préalable de toutes les entités d'un grand ensemble de données alors que vous n'en avez finalement pas besoin de toutes .

Dans Hibernate, vous pouvez configurer pour charger paresseusement une collection d'entités enfants. Le chargement paresseux proprement dit est alors effectué dans les méthodes de l ' PersistentSetqu'Hibernate utilise «sous le capot» pour attribuer la collection d'entités comme Set.

Par exemple

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();
}
BalusC
la source
25

Martin Fowler définit le modèle de chargement différé dans les modèles d'architecture d'application d'entreprise en tant que tel:

Un objet qui ne contient pas toutes les données dont vous avez besoin mais qui sait comment les obtenir.

Ainsi, lors du chargement d'un objet donné, l'idée est de ne pas charger le ou les objets associés que vous ne pouvez pas utiliser immédiatement pour économiser le coût de performance associé. Au lieu de cela, les objets associés seront chargés uniquement lorsqu'ils sont utilisés.

Ce modèle n'est pas spécifique à l'accès aux données et à Hibernate, mais il est particulièrement utile dans ces domaines et Hibernate prend également en charge le chargement paresseux des associations un-à-plusieurs et des associations à un seul point (un-à-un et plusieurs-à-un) également sous certaines conditions. L'interaction paresseuse est abordée plus en détail au chapitre 19 de la documentation de référence d'Hibernate 3.0.

Pascal Thivent
la source
15

Le chargement par défaut par défaut est vrai. Le chargement paresseux signifie que lorsque la requête de sélection est exécutée, elle n'atteindra pas la base de données. Il attendra la fonction getter, c'est-à-dire quand nous en aurons besoin, il ira chercher dans la base de données. par exemple: vous êtes un parent qui a un enfant avec beaucoup de jouets. Mais le problème actuel est que chaque fois que vous l'appelez (nous supposons que vous avez un garçon), il vient à vous avec tous ses jouets. Maintenant, c'est un problème car vous ne voulez pas qu'il porte ses jouets tout le temps. Donc, étant le parent rationnel, vous allez tout de suite et définissez les jouets de l'enfant comme LAZY. Maintenant, chaque fois que vous l'appelez, il vient à vous sans ses jouets.

Chandresh Solanki
la source
11

La récupération différée décide de charger les objets enfants lors du chargement de l'objet parent. Vous devez définir ce fichier de mappage de mise en veille prolongée respectif de la classe parente. Lazy = true(signifie ne pas charger l'enfant) Par défaut, le chargement différé des objets enfants est vrai.

Cela garantit que les objets enfants ne sont pas chargés à moins qu'ils ne soient explicitement appelés dans l'application en appelant la getChild()méthode sur le parent.Dans ce cas, hibernate émet un nouvel appel à la base de données pour charger l'enfant lorsqu'il getChild()est effectivement appelé sur l'objet Parent.

Mais dans certains cas, vous devez charger les objets enfants lorsque le parent est chargé. Faites simplement le lazy = false et hibernate chargera l'enfant lorsque le parent sera chargé à partir de la base de données.

Exemple: si vous avez une TABLE? EMPLOYEE mappé à l'objet Employé et contient un ensemble d'objets Adresse. Classe parente: classe d'employé, classe enfant: classe d'adresse

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; 
} 
} 

Dans le fichier Employee.hbm.xml

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

Dans la configuration ci-dessus. Si lazy="false": - lorsque vous chargez l'objet Employee, cet objet enfant Time Address est également chargé et défini sur la méthode setAddresss (). Si vous appelez employee.getAdress (), les données chargées sont renvoyées. Aucun nouvel appel de base de données.

Si lazy="true": - C'est la configuration par défaut. Si vous ne le mentionnez pas, mettez en veille prolongée, considérez lazy = true. lorsque vous chargez l'objet Employee, l'objet enfant Adress n'est pas chargé. Vous avez besoin d'un appel supplémentaire à la base de données pour obtenir des objets d'adresse. Si vous appelez, employee.getAdress()cette requête de base de données de temps se déclenche et renvoie des résultats. Nouvel appel à la base de données.

Bhavin Shah
la source
L'employé et l'adresse n'ont pas de relation parent-enfant dans ce scénario. C'est une relation «has-a» !
Ram
Il s'agit d'agrégation et non d'héritage.
Rishi
11

En langage profane, c'est comme si vous faisiez un gâteau et que vous aurez besoin de 5 à 10 ingrédients du réfrigérateur. Vous avez deux options: obtenir tous les ingrédients du réfrigérateur et les placer sur la plate-forme de votre cuisine, ou apporter l'article que vous voulez quand vous en avez besoin.

De même, dans le chargement hâtif, vous récupérez toutes les informations sur le bean et ses classes associées (pas une relation enfant ou is-a mais a une relation, c'est-à-dire que le gâteau a de la farine, a du lait, a de la crème, etc.), et en cas de chargement paresseux, d'abord vous n'apportez que son identifiant et ses valeurs qui proviennent de la même table (ingrédients nécessaires dont vous aurez d'abord besoin dans votre bol en cas de gâteau). Toutes les informations provenant d'autres tables seront récupérées au fur et à mesure des besoins / utilisés.

Keyur
la source
8

Chargement paresseux? Eh bien, cela signifie simplement que les enregistrements enfants ne sont pas récupérés immédiatement, mais automatiquement dès que vous essayez d'y accéder.

Steffen
la source
3

Le paramètre Lazy décide de charger les objets enfants lors du chargement de l'objet parent.Vous devez faire ce paramètre le fichier de mappage d'hibernation respectif de la classe parent.Lazy = true (signifie ne pas charger l'enfant) Par défaut, le chargement différé des objets enfants est true . Cela garantit que les objets enfants ne sont pas chargés à moins qu'ils ne soient explicitement appelés dans l'application en appelant la méthode getChild () sur le parent.Dans ce cas, hibernate émet un nouvel appel de base de données pour charger l'enfant lorsque getChild () est effectivement appelé sur le parent. Mais dans certains cas, vous devez charger les objets enfants lorsque le parent est chargé. Faites simplement le lazy = false et hibernate chargera l'enfant lorsque le parent est chargé à partir de la base de données.Exampleslazy = true (par défaut) L'adresse enfant de la classe User peut être rendue paresseuse si elle n'est pas requise fréquemment.

Siva Chimpiri
la source
3

Le chargement différé vous permet de différer la récupération de l'association ou d'avoir un meilleur contrôle sur la stratégie de récupération.

Lorsque vous utilisez le chargement EAGER, vous définissez un plan d'extraction global qui ne peut pas être remplacé au moment de la requête, ce qui signifie que vous êtes limité à une décision que vous avez prise lors de la conception de votre modèle d'entité. La récupération EAGER est une odeur de code , car la stratégie de récupération est une stratégie de temps de requête et elle peut différer d'un cas d'utilisation métier à un autre.

La stratégie de récupération est un aspect très important, car trop de récupération EAGER peut entraîner de graves problèmes liés aux performances.

Vlad Mihalcea
la source
2

Le chargement différé est un modèle de conception couramment utilisé dans la programmation informatique pour différer l'initialisation d'un objet jusqu'au point où il est nécessaire. Il peut contribuer à l'efficacité du fonctionnement du programme s'il est utilisé correctement et de manière appropriée

Wikipédia

Lien de chargement paresseux depuis hibernate.org

Diego Dias
la source
1

Eh bien, cela signifie simplement charger les données dont vous avez besoin actuellement au lieu de charger tout un tas de données à la fois que vous n'utiliserez pas maintenant. Ainsi, le temps de chargement des applications est plus rapide que d'habitude.

Abhinaya Pandey
la source
0

Hiberante prend en charge la fonctionnalité d'initialisation différée pour les entités et les collections. Le moteur Hibernate charge uniquement les objets que nous recherchons, pas les autres entités ou collections.

lazy = "false" par défaut, la mention d'initialisation de chargement pour le seul enfant est lazy.si true, le parent est en cours de chargement ne prend pas en charge l'enfant

abburi
la source
0

Le paramètre Lazy décide de charger les objets enfants lors du chargement de l'objet parent.Vous devez faire ce paramètre le fichier de mappage d'hibernation respectif de la classe parent.Lazy = true (signifie ne pas charger l'enfant) Par défaut, le chargement différé des objets enfants est true .

Manikandan Adhimoolam
la source
0

Étonnamment, aucune des réponses ne parle de la façon dont cela est réalisé en hibernation derrière les écrans.

Le chargement différé est un modèle de conception qui est efficacement utilisé en veille prolongée pour des raisons de performances qui impliquent les techniques suivantes.


1. Instrumentation de code d'octet :

Améliore la définition de la classe de base avec des crochets d' hibernation pour intercepter tous les appels à cet objet entité.

Fait soit au moment de la compilation, soit au moment de l'exécution [load]

1.1 Temps de compilation

  • Opération de post-compilation

  • Surtout par les plugins maven / ant

1.2 Temps d'exécution

  • Si aucune instrumentation au moment de la compilation n'est effectuée, celle-ci est créée au moment de l'exécution à l'aide de bibliothèques telles que javassist

2. Proxies

L'objet entité renvoyé par Hibernate est un proxy du type réel.

Voir aussi: Javassist. Quelle est l'idée principale et où une réelle utilisation?

Sankarganesh Eswaran
la source