Proxy dans la méthode load () Hibernate

Proxy dans la méthode load () Hibernate

1. Vue d'ensemble

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

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

2. Une brève introduction aux proxies et à la méthodeload()

By definition, a proxy is “a function authorized to act as the deputy or substitute for another”.

Cela s'applique à Hibernate lorsque nous appelonsSession.load() pour créer ce que l'on appelle ununinitialized proxy de la classe d'entité souhaitée.

En termes simples, Hibernate sous-classe notre classe d'entité, en utilisant la bibliothèqueCGLib. En dehors de 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 qu'une des méthodes d'entité est appelée, l'entité est chargée et à ce stade devient uninitialized proxy.

3. Proxies et Lazyloadchantent

3.1. Une seule entité

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

Si nous utilisonsSession.load() pour instancier unEmployee:

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

Ensuite, Hibernate créera un proxy non initialisé deEmployee. It will contain the ID that we gave it but otherwise will have no other values because we haven’t hit the database yet.

Cependant, une fois que nous appelons une méthode suralbert:

String firstName = albert.getFirstName();

Ensuite, Hibernate interrogera la table de base de donnéesemployee pour une entité avec une clé primaire de 1, en remplissantalbert avec ses propriétés à partir de la ligne correspondante.

S'il ne parvient pas à trouver une ligne, Hibernate lance unObjectNotFoundException.

3.2. Relations un à plusieurs

Maintenant, créons également une sentitéCompany , où unCompany partage plusieursEmployees:

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

Si nous utilisons cette foisSession.load() fils la société:

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 appelionsgetEmployees en fonction de la stratégie de récupération.

3.3. Relations plusieurs-à-un

Le cas est similaire dans le sens opposé:

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

Si nous utilisons à nouveauload():

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

bob will maintenant être initialisé, et en fait,workplace sera maintenant défini pour être un proxy non initialisé en fonction de la stratégie de récupération.

4. Chargement paresseux

Désormais,load() won ne nous donne pas toujours un proxy non initialisé. En fait, leSession java doc nous rappelle (italiques ajoutés):

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

Un exemple simple de ce qui peut arriver est la taille du lot.

Disons que nous utilisons@BatchSize sur notre sentité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 appelonsgetFirstName filscatherine:

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, lorsque nous appelons le prénom dedarrell:

String darrell = darrell.getFirstName();

PuisHibernate doesn’t hit the database at all.

5. Chargement avide

5.1. Utilisation deget()

Nous pouvons également contourner complètement les proxies et demander à Hibernate de charger la chose réelle en utilisantSession.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'unObjectNotFoundException, il renverranull sifinnigan  n'existe pas.

5.2. Implications sur les performances

Alors queget() est pratique,load() peut être plus léger sur la base de données.

Par exemple, disons quegerald  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 changer l'enregistrement deemployee que dans cette situation, l'appel de, àload() pourCompany  est raisonnable.

Si nous avons appeléget() surCompany, alors nous aurions chargé toutes ses données inutilement à partir de la base de données.

6. Conclusion

Dans cet article, nous avons brièvement appris comment fonctionnent les proxysHibernate et comment cela affecte la méthodeload avec les entités et leurs relations.

Nous avons également examiné rapidement en quoiload() diffère deget().

Comme d'habitude, le code source complet qui accompagne le tutoriel est disponibleover on GitHub.