Eager/Lazy Loading dans Hibernate

Eager/Lazy Loading In Hibernate

1. introduction

Lorsque vous travaillez avec un ORM, l'extraction / le chargement de données peut être classé en deux types: désireux et paresseux.

Dans cet article rapide, nous allons souligner les différences et montrer que celles-ci peuvent être utilisées dans Hibernate.

2. Dépendances Maven

Pour utiliser Hibernate, définissons d'abord la dépendance principale dans nospom.xml:


    org.hibernate
    hibernate-core
    5.2.2.Final

La dernière version d'Hibernate peut être trouvéehere.

3. Chargement avide et paresseux

La première chose que nous devrions discuter ici est ce que le chargement paresseux et le chargement empressé sont:

  • Eager Loading est un modèle de conception dans lequel l'initialisation des données se produit sur place

  • Lazy Loading est un modèle de conception utilisé pour différer l'initialisation d'un objet aussi longtemps que possible

Voyons comment cela fonctionne avec quelques exemples:

La classeUserLazy:

@Entity
@Table(name = "USER")
public class UserLazy implements Serializable {

    @Id
    @GeneratedValue
    @Column(name = "USER_ID")
    private Long userId;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
    private Set orderDetail = new HashSet();

    // standard setters and getters
    // also override equals and hashcode

}

La classeOrderDetail:

@Entity
@Table (name = "USER_ORDER")
public class OrderDetail implements Serializable {

    @Id
    @GeneratedValue
    @Column(name="ORDER_ID")
    private Long orderId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="USER_ID")
    private UserLazy user;

    // standard setters and getters
    // also override equals and hashcode

}

UnUser peut avoir plusieursOrderDetails. In eager loading strategy, if we load the User data, it will also load up all orders associated with it and will store it in a memory.

Mais, lorsque le chargement différé est activé, si nous récupérons unUserLazy, les données deOrderDetail ne seront pas initialisées et chargées dans une mémoire tant qu’un appel explicite n’y sera pas fait.

Dans la section suivante, nous verrons comment l'exemple ci-dessus est implémenté dans Hibernate.

4. Chargement de la configuration

Dans cette section, nous verrons comment configurer des stratégies de récupération dans Hibernate. Nous allons réutiliser les exemples de la section précédente.

Le chargement différé peut être simplement activé à l'aide du paramètre d'annotation suivant:

fetch = FetchType.LAZY

Pour utiliser Eager Fetching, le paramètre suivant est utilisé:

fetch = FetchType.EAGER

Pour configurer Eager Loading, nous avons utilisé la classe jumelle deUserLazy appeléeUserEager.

Dans la section suivante, nous examinerons les différences entre les deux types de récupération.

5. Différences

Comme nous l'avons mentionné, la principale différence entre les deux types de récupération est le moment où les données sont chargées dans une mémoire.

Jetons un œil à cet exemple:

List users = sessionLazy.createQuery("From UserLazy").list();
UserLazy userLazyLoaded = users.get(3);
return (userLazyLoaded.getOrderDetail());

Avec l'approche d'initialisation paresseuse,orderDetailSet ne sera initialisé que lorsqu'il est explicitement appelé à l'aide d'un getter ou d'une autre méthode, comme indiqué dans l'exemple ci-dessus:

UserLazy userLazyLoaded = users.get(3);

Mais avec une approche impatiente enUserEager, il sera initialisé immédiatement dans la première ligne de l'exemple ci-dessus:

List user = sessionEager.createQuery("From UserEager").list();

Pour le chargement différé, un objet proxy est utilisé et une requête SQL distincte est lancée pour charger lesorderDetailSet.

L'idée de désactiver les serveurs mandataires ou de charger paresseux est considérée comme une mauvaise pratique chez Hibernate. Cela peut entraîner l'extraction d'une grande quantité de données d'une base de données et leur stockage dans une mémoire, quel que soit le besoin.

La méthode suivante peut être utilisée pour tester la fonctionnalité ci-dessus:

Hibernate.isInitialized(orderDetailSet);

Maintenant, il est important d’examiner les requêtes générées dans les deux cas:

true

Le paramètre ci-dessus dans lesfetching.hbm.xml affiche les requêtes SQL générées. Si vous regardez une sortie de console, vous pourrez voir les requêtes générées.

Pour le chargement différé, la requête qui est générée pour charger les donnéesUser:

select user0_.USER_ID as USER_ID1_0_,  ... from USER user0_

Cependant, lors d'un chargement impatient, nous avons vu une jointure se faire avecUSER_ORDER:

select orderdetai0_.USER_ID as USER_ID4_0_0_, orderdetai0_.ORDER_ID as ORDER_ID1_1_0_, orderdetai0_ ...
  from USER_ORDER orderdetai0_ where orderdetai0_.USER_ID=?

La requête ci-dessus est générée pour tous lesUsers, ce qui entraîne l'utilisation de beaucoup plus de mémoire que dans l'autre approche.

6. Avantages et inconvénients

6.1. Chargement paresseux

Avantages:

  • Temps de chargement initial beaucoup plus petit que dans l'autre approche

  • Moins de consommation de mémoire que dans l'autre approche

Désavantages:

  • Une initialisation retardée peut avoir un impact sur les performances pendant les moments indésirables.

  • Dans certains cas, vous devez manipuler les objets initialisés avec un soin particulier ou vous risquez de vous retrouver avec une exception.

6.2. Chargement impatient:

Avantages:

  • Pas d'impacts sur les performances liées à l'initialisation retardée

Désavantages:

  • Long temps de chargement initial

  • Charger trop de données inutiles peut affecter les performances

7. Chargement paresseux dans Hibernate

Hibernate applies lazy loading approach on entities and associations by providing a proxy implementation de classes.

Hibernate intercepte les appels d’une entité en lui substituant un proxy dérivé de la classe d’une entité. Dans notre exemple, lorsqu'une information demandée est manquante, elle sera chargée à partir d'une base de données avant que le contrôle ne soit cédé à l'implémentation de la classeUser.

Il convient également de noter que lorsque l'association est représentée comme une classe de collection (dans les exemples ci-dessus, elle est représentée parSet<OrderDetail> orderDetailSet), un wrapper est créé et remplacé par une collection originale.

Pour en savoir plus sur le modèle de conception de proxy, vous pouvez faire référence àhere.

8. Conclusion

Dans cet article, nous avons montré les exemples des deux principaux types de récupération utilisés dans Hibernate.

Pour une expertise de niveau avancé, vous pouvez consulter le site officiel d'Hibernate. Pour obtenir le code décrit dans cet article, veuillez jeter un œil à cerepository.