Un plan d'extraction (FetchPlan) est la stratégie utilisée par EntityManager pour extraire des objets associés si l'application doit accéder aux relations.
Supposons que votre application comporte deux entités : Service et Employé. La relation entre l'entité Service et l'entité Employé est une relation un à plusieurs bidirectionnelle : un service comporte plusieurs employés et un employé appartient à un seul service. Etant donné que dans la plupart des cas, lorsque l'entité Service est extraite, les employés correspondants doivent être extraits, le type d'extraction de cette relation un à plusieurs sera défini comme EAGER.
Voici un fragment de code de la classe Service (Department).
@Entity
public class Department {
@Id
private String deptId;
@Basic
String deptName;
@OneToMany(fetch = FetchType.EAGER, mappedBy="department", cascade = {CascadeType.PERSIST})
public Collection<Employee> employees;
}
Dans un environnement réparti, lorsqu'une application appelle em.find(Department.class, "dept1") pour trouver une entité Service avec la clé "dept1", cette opération find retourne l'entité Service et toutes les relations d'extraction hâtive. Dans le cas du fragment de code précédent, il s'agit de tous les employés du service "dept1".
Dans les versions antérieures à WebSphere eXtreme Scale 6.1.0.5, l'extraction d'une entité Service et de N entités Employé provoquait N+1 transferts client-serveur car le client extrayait une entité pour un transfert client-serveur. Vous pouvez améliorer les performances avec l'extraction de ces N+1 entités en un seul transfert.
Un plan d'extraction peut être utilisé pour personnaliser le mode d'extraction des relations hâtives en adaptant la profondeur maximale des relations. La profondeur d'extraction se substitue davantage aux relations hâtives que la profondeur spécifiée pour les relations lentes. Par défaut, la profondeur d'extraction correspond à la profondeur d'extraction maximale, ce qui implique l'extraction des relations hâtives de tous les niveaux pouvant être parcourues hâtivement depuis l'entité racine. Une relation EAGER peut être parcourue hâtivement depuis une entité racine uniquement si toutes les relations en partant de l'entité racine sont configurées comme extraites hâtivement.
Dans l'exemple précédent, l'entité Employé peut être parcourue hâtivement depuis l'entité Service car la relation Service-Employé est configurée comme étant extraite hâtivement.
Si l'entité Employé présente une autre relation hâtive avec une entité Adresse par exemple, cette dernière peut également être parcourue hâtivement depuis l'entité Service. Toutefois, si les relations Service-Employé ont été configurées en mode d'extraction lente, l'entité Adresse ne peut pas être parcourue hâtivement depuis l'entité Service car la relation Service-Employé rompt la chaîne d'extraction hâtive.
Un objet FetchPlan peut être extrait de l'instance EntityManager. L'application peut utiliser la méthode setMaxFetchDepth pour modifier la profondeur d'extraction maximale.
Un plan d'extraction est associé à une instance EntityManager. Le plan d'extraction s'applique à toutes les opérations fetch, tel que décrit ci-dessous de manière plus spécifique.
L'objet FetchPlan est modifiable. Une fois modifiée, la valeur est appliquée aux opérations fetch exécutées ultérieurement.
Un plan d'extraction est important dans un environnement réparti car il décide si les entités de relation d'extraction hâtive sont extraites avec l'entité racine dans un ou plusieurs transferts client-serveur.
En reprenant l'exemple précédent, considérez que la profondeur maximale du plan d'extraction est infinie. Dans ce cas, lorsqu'une application appelle em.find(Department.class, "dept1") pour trouver une entité Service, cette opération find retourne l'entité Service et N entités Employé dans un transfert client-serveur. Toutefois, pour un plan d'extraction doté d'une profondeur d'extraction maximale égale à zéro, seul l'objet Service est extrait du serveur alors que les entités Employé sont extraites du serveur uniquement lors de l'accès à la collection d'employés de l'objet Service.
Plusieurs plans d'extraction sont disponibles en fonction de vos besoins ; ils sont détaillés dans les sections suivantes.
Impact sur une grille répartie
Dans un environnement client-serveur, si un plan d'extraction à profondeur infinie est utilisé, toutes les relations pouvant être parcourues hâtivement depuis l'entité racine sont extraites dans un transfert client-serveur.
Exemple : si l'application s'intéresse à toutes les entités Adresse de tous les employés d'un Service particulier, elle utilise un plan d'extraction à profondeur infinie pour extraire toutes les entités Adresse associées. Le code suivant implique uniquement un transfert client-serveur.
em.getFetchPlan().setMaxFetchDepth(FetchPlan.DEPTH_INFINITE);
tran.begin();
Department dept = (Department) em.find(Department.class, "dept1");
// Effectuez une action avec l'objet Address.
for (Employee e: dept.employees) {
for (Address addr: e.addresses) {
// effectuez une action avec les adresses.
}
}
tran.commit();
Dans un environnement client-serveur, si un plan d'extraction à profondeur égale à zéro est utilisé, seule l'entité racine est extraite dans le premier transfert client-serveur. Toutes les relations hâtives sont traitées si elles ont été lentes.
Exemple : dans cet exemple, l'application s'intéresse uniquement à l'attribut entité Service. Elle n'a pas besoin d'accéder aux employés correspondants et définit donc la profondeur du plan d'extraction sur 0.
Session session = objectGrid.getSession();
EntityManager em = session.getEntityManager();
EntityTransaction tran = em.getTransaction();
em.getFetchPlan().setMaxFetchDepth(0);
tran.begin();
Department dept = (Department) em.find(Department.class, "dept1");
// effectuez une action avec l'objet dept.
tran.commit();
Parler de plan d'extraction à profondeur k- signifie que la profondeur maximale des extractions réalisées par ce plan est de k.
éDans un environnement client-serveur eXtreme Scale, si un plan d'extraction à profondeur k-est utilisé, toutes les relations pouvant être parcourues hâtivement depuis l'entité racine en k étapes sont extraites dans le premier transfert client-serveur.
Le plan d'extraction à profondeur infinie (k = infini) et le plan d'extraction à profondeur égale à zéro (k = 0) sont seulement deux exemples de plan d'extraction à profondeur k-.
Pour développer l'exemple précédent, supposons qu'une autre relation hâtive existe entre l'entité Employé et l'entité Adresse. Si la profondeur d'extraction maximale du plan d'extraction est égale à 1, l'opération em.find(Department.class, "dept1") extrait l'entité Service et toutes les entités Employé dans un transfert client-serveur. Toutefois, les entités Adresse ne sont pas extraites car elles ne peuvent pas être parcourues hâtivement dans l'entité Service en une seule étape ; elles requièrent deux étapes.
Si la profondeur d'extraction maximale d'un plan d'extraction est égale à 2, l'opération em.find(Department.class, "dept1") extrait l'entité Service, toutes les entités Employé et toutes les entités Adresse associées aux entités Employés dans un transfert client-serveur.
Si vous exécutez une requête d'entité, vous pouvez également utiliser un plan d'extraction pour personnaliser l'extraction des relations.
Par exemple, le résultat de la requête SELECT d FROM Department d WHERE "d.deptName='Department'" présente une relationà l'entité Service. Notez que la profondeur du plan d'extraction commence avec l'association du résultat de la requête, dans ce cas, l'entité Service et non le résultat de la requête lui-même. L'entité Service est au niveau de profondeur d'extraction 0. Par conséquent, un plan d'extraction doté d'une profondeur d'extraction maximale de 1 extrait l'entité Service et les entités Employé correspondantes dans un seul transfert client-serveur.
Exemple : dans cet exemple, la profondeur du plan d'extraction est définie sur 1, de sorte que l'entité Service et les entités Employé sont extraites dans un transfert client-serveur mais les entités Adresse ne sont pas extraites dans le même transfert.
Par défaut, toutes les relations pouvant être parcourues hâtivement depuis l'entité racine sont extraites en un seul transfert client-serveur. Ce mode de transfert peut améliorer les performances si toutes les relations sont amenées à être utilisées. Toutefois, dans certains scénarios d'utilisation, les relations pouvant être parcourues hâtivement depuis l'entité racine ne sont pas toutes utilisées, ce qui entraîne des frais d'exécution et une sollicitation de la bande passante en raison de l'extraction de ces entités superflues.
Dans ces cas de figure, l'application peut définir la profondeur d'extraction maximale sur une valeur faible afin de réduire la profondeur des entités à extraire en rendant lentes toutes les relations hâtives au-delà de ce niveau de profondeur. Ce paramètre peut améliorer les performances.
En reprenant l'exemple Service-Employé-Adresse précédent, par défaut, toutes les entités Adresse associées aux employés du Service "dept1" sont extraites lorsque em.find(Department.class, "dept1") est appelée. Si l'application n'utilise pas les entités Adresse, elle peut définir la profondeur d'extraction maximale sur 1, de sorte que les entités Adresse ne sont pas extraites avec l'entité Service.