web-dev-qa-db-fra.com

Différence entre JOIN et JOIN FETCH dans Hibernate

S'il vous plaît, aidez-moi à comprendre où utiliser un JOIN régulier et où JOIN FETCH.

Par exemple, si nous avons ces deux requêtes

FROM Employee emp
JOIN emp.department dep

et

FROM Employee emp
JOIN FETCH emp.department dep

Y a-t-il une différence entre eux? Si oui, lequel utiliser quand?

145
abbas

Dans ces deux requêtes, vous utilisez JOIN pour interroger tous les employés auxquels au moins un département est associé.

Mais la différence est la suivante: dans la première requête, vous ne renvoyez que les Employés pour Hibernate. Dans la deuxième requête, vous renvoyez les employés et tous les départements associés.

Ainsi, si vous utilisez la deuxième requête, vous n'aurez pas besoin de créer une nouvelle requête pour consulter à nouveau la base de données afin de voir les départements de chaque employé.

Vous pouvez utiliser la deuxième requête lorsque vous êtes certain d'avoir besoin du département de chaque employé. Si vous n'avez pas besoin du département, utilisez la première requête.

Je vous recommande de lire ce lien si vous devez appliquer une condition WHERE (ce dont vous aurez probablement besoin): Comment exprimer correctement JPQL "join fetch" avec la clause "where" en tant que JPA 2 CriteriaQuery?

Mettre à jour

Si vous n'utilisez pas fetch et que les services continuent à être renvoyés, c'est que votre correspondance entre l'employé et le service (un @OneToMany) est définie avec FetchType.EAGER. Dans ce cas, toute requête HQL (avec fetch ou non) avec FROM Employee apportera tous les départements. N'oubliez pas que tous les mappages * ToOne (@ManyToOne et @OneToOne) sont EAGER par défaut.

151
Dherik

dans ce lien je l'ai mentionné auparavant sur le commentaire, lisez cette partie:

Une jointure "fetch" permet d’initialiser des associations ou des ensembles de valeurs avec leurs objets parents à l’aide d’une seule sélection. Ceci est particulièrement utile dans le cas d'une collection. Il remplace en fait les déclarations de jointure externe et différée du fichier de mappage pour les associations et les collections.

cet effet "JOIN FETCH" aura son effet si vous avez la propriété (fetch = FetchType.LAZY) pour une collection dans l'entité (exemple ci-dessous).

Et ce n'est que l'effet de la méthode de "quand la requête devrait se passer". Et vous devez aussi savoir this :

hibernate a deux notions orthogonales: quand l’association est-elle extraite et comment est-elle extraite? Il est important de ne pas les confondre. Nous utilisons fetch pour optimiser les performances. Nous pouvons utiliser paresseux pour définir un contrat pour quelles données sont toujours disponibles dans une instance détachée d'une classe particulière.

quand l'association est-elle récupérée -> votre type "FETCH"

comment est-il récupéré -> Joindre/sélectionner/sous-sélectionner/lot

Dans votre cas, FETCH n'aura son effet que si vous avez le département en tant qu'ensemble dans Employee, quelque chose comme ceci dans l'entité:

@OneToMany(fetch = FetchType.LAZY)
private Set<Department> department;

quand vous utilisez

FROM Employee emp
JOIN FETCH emp.department dep

vous obtiendrez emp et emp.dep. quand vous n'avez pas utilisé chercher, vous pouvez toujours obtenir emp.dep mais hibernate traitera une autre sélection dans la base de données pour obtenir cet ensemble de services.

il s’agit donc simplement d’optimiser les performances. Vous voulez obtenir tous les résultats (que vous en ayez besoin ou non) en une seule requête (extraction anticipée), ou vous souhaitez l’interroger ultérieurement lorsque vous en avez besoin (extraction différée).

Utilisez une extraction rapide lorsque vous avez besoin d’obtenir de petites données avec une seule requête (une seule grande requête). Ou utilisez la récupération paresseuse pour interroger ce dont vous avez besoin (beaucoup de requêtes plus petites).

utilisez fetch quand:

  • pas de grande collection inutile à l'intérieur de cette entité que vous êtes sur le point d'obtenir

  • communication du serveur d'application vers serveur de base de données trop éloignée et nécessite une longue période

  • vous pouvez avoir besoin de cette collection plus tard si vous n’avez pas accès à celle-ci ( en dehors de du transaction ( méthode/classe)

55
Angga

Si le mappage @oneToOne est défini sur FetchType.LAZY et que vous utilisez une seconde requête (car vous devez charger des objets Department dans le cadre des objets Employee), Hibernate émettra des requêtes pour extraire des objets Department pour chaque objet Employee. il va chercher chez DB. Plus tard dans le code, vous pourrez accéder aux objets Département via l'association à valeur unique Employé à département et Hibernate n'émettra aucune requête pour extraire un objet Département pour l'employé donné. Rappelez-vous qu'Hibernate émet toujours des requêtes égales au nombre d'employés qu'il a récupérés. Hibernate émettra le même nombre de requêtes dans les deux requêtes ci-dessus si vous souhaitez accéder aux objets Department de tous les objets Employee.

4
Bunti

Dherik: Je ne suis pas sûr de ce que vous dites. Lorsque vous n'utilisez pas chercher, le résultat sera de type: List<Object[ ]>, ce qui signifie une liste de tables Object et non une liste d'employés.

Object[0] refers an Employee entity 
Object[1] refers a Departement entity 

Lorsque vous utilisez la fonction de récupération, il n’ya qu’une sélection et le résultat est la liste Employé List<Employee> contenant la liste des services. Il remplace la déclaration paresseuse de l'entité.

1
Bilal BBB