Proxy dans la méthode Hibernate load ()

1. Vue d'ensemble

Dans ce tutoriel, nous verrons ce qu'est un proxy dans le contexte de la méthode load () d'Hibernate .

Pour les lecteurs qui découvrent Hibernate, envisagez d'abord de vous familiariser avec les bases.

2. Brève introduction aux proxies et à la méthode load ()

Par définition, un mandataire est «une fonction autorisée à agir en tant que suppléant ou suppléant d'une autre» .

Cela s'applique à Hibernate lorsque nous appelons Session.load () pour créer ce qu'on appelle un proxy non initialisé de la classe d'entité souhaitée.

En termes simples, Hibernate sous-classe notre classe d'entité, en utilisant la bibliothèque CGLib . A part la méthode @Id , l'implémentation du proxy délègue toutes les autres méthodes de propriété à la session Hibernate pour remplir l'instance, un peu comme:

public class HibernateProxy extends MyEntity {     private MyEntity target;     public String getFirstName() {         if (target == null) {             target = readFromDatabase();         }         return target.getFirstName();     } }

Cette sous-classe sera celle à renvoyer au lieu d'interroger directement la base de données.

Une fois que l'une des méthodes d'entité est appelée, l'entité est chargée et à ce stade devient un proxy initialisé.

3. Proxies et chargement différé

3.1. Une seule entité

Pensons à l' employé en tant qu'entité. Pour commencer, nous supposerons qu'il n'a aucun rapport avec d'autres tables.

Si nous utilisons Session.load () pour instancier un employé :

Employee albert = session.load(Employee.class, new Long(1));

Ensuite, Hibernate créera un proxy non initialisé d' employé . Il contiendra l'ID que nous lui avons donné, mais sinon, il n'aura pas d'autres valeurs car nous n'avons pas encore atteint la base de données.

Cependant, une fois que nous appelons une méthode sur albert :

String firstName = albert.getFirstName();

Ensuite, Hibernate interrogera la table de base de données des employés pour une entité avec une clé primaire de 1, remplissant albert avec ses propriétés à partir de la ligne correspondante.

S'il ne parvient pas à trouver une ligne, Hibernate lève une ObjectNotFoundException .

3.2. Relations un-à-plusieurs

Maintenant, créons également une entité Entreprise , où une entreprise compte de nombreux employés:

public class Company {     private String name;     private Set employees; }

Si nous utilisons cette fois Session.load () sur l'entreprise:

Company bizco = session.load(Company.class, new Long(1)); String name = bizco.getName();

Ensuite, les propriétés de l'entreprise sont remplies comme avant, sauf que l'ensemble des employés est juste un peu différent.

Vous voyez, nous n'avons demandé que la ligne de l'entreprise, mais le proxy laissera l'employé seul jusqu'à ce que nous appelions getEmployees en fonction de la stratégie de récupération.

3.3. Relations plusieurs-à-un

Le cas est similaire dans la direction opposée:

public class Employee {     private String firstName;     private Company workplace; }

Si nous utilisons à nouveau load () :

Employee bob = session.load(Employee.class, new Long(2)); String firstName = bob.getFirstName();

bob sera maintenant initialisé et, en fait, le lieu de travail sera désormais défini comme un proxy non initialisé en fonction de la stratégie de récupération.

4. Chargement paresseux

Maintenant, load () ne nous donnera pas toujours un proxy non initialisé. En fait, le document java Session nous rappelle (italiques ajoutés):

Cette méthode peut renvoyer une instance mandatée qui est initialisée à la demande, lors de l'accès à une méthode sans identifiant.

Un exemple simple de quand cela peut arriver est la taille du lot.

Disons que nous utilisons @BatchSize sur notre entité Employee :

@Entity @BatchSize(size=5) class Employee { // ... }

Et cette fois, nous avons trois employés:

Employee catherine = session.load(Employee.class, new Long(3)); Employee darrell = session.load(Employee.class, new Long(4)); Employee emma = session.load(Employee.class, new Long(5));

Si nous appelons getFirstName sur catherine :

String cathy = catherine.getFirstName();

Ensuite, en fait, Hibernate peut décider de charger les trois employés à la fois, les transformant tous les trois en proxys initialisés.

Et puis, quand nous demandons le prénom de darrell :

String darrell = darrell.getFirstName();

Alors Hibernate n'atteint pas du tout la base de données.

5. Chargement impatient

5.1. Utiliser get ()

Nous pouvons également contourner complètement les proxys et demander à Hibernate de charger la chose réelle en utilisant Session.get () :

Employee finnigan = session.get(Employee.class, new Long(6));

Cela appellera la base de données immédiatement, au lieu de renvoyer un proxy.

Et en fait, au lieu d'une ObjectNotFoundException , elle retournera null si finnigan n'existe pas.

5.2. Implications sur les performances

Bien que get () soit pratique, load () peut être plus léger sur la base de données.

Par exemple, disons que Gerald va travailler pour une nouvelle entreprise:

Employee gerald = session.get(Employee.class, new Long(7)); Company worldco = (Company) session.load(Company.class, new Long(2)); employee.setCompany(worldco); session.save(employee);

Puisque nous savons que nous n'allons modifier l' enregistrement de l' employé que dans cette situation , appeler load () pour Company est judicieux.

Si nous appelions get () sur Company , alors nous aurions chargé toutes ses données inutilement de la base de données.

6. Conclusion

Dans cet article, nous avons brièvement appris comment fonctionnent les proxys Hibernate et comment cela affecte la méthode de chargement avec les entités et leurs relations.

De plus, nous avons examiné rapidement en quoi load () diffère de get ().

Comme d'habitude, le code source complet qui accompagne le didacticiel est disponible à l'adresse over sur GitHub.