Ein Abrufplan (Objekt "FetchPlan") ist die Strategie, die der Entitätsmanager für den Abruf zugeordneter Objekte verwendet, wenn die Anwendung auf Beziehungen zugreifen muss.
Angenommen, Ihre Anwendung hat zwei Entitäten: Department (Abteilung) und Employee (Mitarbeiter). Die Beziehung zwischen der Entität "Department" und der Entität "Employee" ist eine bidirektionale 1:N-Beziehung: Eine Abteilung hat viele Mitarbeiter, und ein Mitarbeiter gehört zu einer einzigen Abteilung. Da beim Abrufen der Entität "Department" meistens auch die Mitarbeiter abgerufen werden, wird der Abruftyp dieser 1:N-Beziehung auf EAGER (Vorsorglich) gesetzt.
Im Folgenden sehen Sie ein Snippet der Klasse "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;
}
Wenn eine Anwendung in einer verteilten Umgebung em.find(Department.class, "dept1") aufruft, um eine Entität "Department" mit dem Schlüssel "dept1" zu suchen, findet diese Suchoperation die Entität "Department" und alle Relationen vom Typ "eager-fetched". Im Fall des vorherigen Snippets sind dies alle Mitarbeiter der Abteilung "dept1".
In den Versionen vor WebSphere eXtreme Scale 6.1.0.5 finden beim Abrufen einer Entität "Department" und N Entitäten "Employee" N+1 Client/Server-Austauschoperationen statt, weil der Client nur eine einzige Entität pro Client/Server-Austausch abruft. Sie können die Leistung verbessern, wenn Sie diese N+1 Entitäten in einem einzigen Austausch abrufen.
Ein Abrufplan (FetchPlan) kann verwendet werden, um um festzulegen, wie Beziehungen vom Typ "eager" abgerufen werden, indem die maximale Beziehungstiefe angepasst wird. Die Abruftiefe setzt alle Relationen vom Typ "eager" auf "lazy", die größer sind als die festgelegte Abruftiefe. Standardmäßig ist die Abruftiefe die maximale Abruftiefe. Das bedeutet, dass Beziehungen vom Typ "eager" aller Ebenen, die aus Eager-Sicht über die Stammentität erreicht werden können, abgerufen werden. Eine Beziehung vom Typ "eager" ist nur dann aus Eager-Sicht über eine Stammentität erreichbar, wenn alle Beziehungen ausgehend von der Stammentität zu dieser Eager-Beziehung als Eager-Fetched-Beziehungen konfiguriert sind.
Im vorherigen Beispiel ist die Entität "Employee" über die Entität "Department" aus Eager-Sicht erreichbar, weil die Beziehung zwischen Department und Employee als Eager-Fetched-Beziehung konfiguriert ist.
Wenn die Entität "Employee" beispielsweise eine weitere Eager-Beziehung zu einer Entität "Address" hat, ist die Entität "Address" aus Eager-Sicht ebenfalls über die Entität "Department" erreichbar. Sind die Department-Employee-Beziehungen jedoch als Lazy-Fetched-Beziehungen konfiguriert, ist die Entität "Address" aus Eager-Sicht nicht über die Entität "Department" erreichbar, weil die Department-Employee-Beziehung die Eager-Fetch-Kette unterbricht.
Ein FetchPlan-Objekt kann von der EntityManager-Instanz abgerufen werden. Die Anwendung kann die Methode "setMaxFetchDepth" verwenden, um die maximale Abruftiefe zu ändern.
Ein Abrufplan wird einer EntityManager-Instanz zugeordnet. Der Abrufplan gilt für jede Abrufoperation, die im Folgenden einzeln aufgeführt sind:
Das FetchPlan-Objekt ist veränderlich. Sobald das Objekt geändert wird, wird der geänderte Wert auf die anschließend ausgeführten Abrufoperationen angewendet.
Ein Abrufplan ist für eine verteilte Implementierung wichtig, weil er entscheidet, ob die Eager-Fetched-Beziehungsentitäten mit der Stammentität in einer einzigen oder in mehreren Client/Server-Austauschoperationen abgerufen werden.
Stellen Sie sich als Fortsetzung des vorherigen Beispiels vor, dass der Abrufplan eine definierte maximale Tiefe von unbegrenzt hat. Wenn eine Anwendung in diesem Fall em.find(Department.class, "dept1") aufruft, um eine Abteilung (Department) zu suchen, ruft diese Suchoperation eine einzige Department-Entität und N Employee-Entitäten in einer einigen Client/Server-Austauschoperation ab. Bei einem Abrufplan mit einer maximalen Abruftiefe von null wird jedoch nur das Department-Objekt vom Server abgerufen, während die Employee-Entitäten nur dann vom Server abgerufen werden, wenn auf die Employee-Sammlung des Department-Objekts zugegriffen wird.
Sie haben mehrere verschiedene Abrufpläne, die auf Ihren Anforderungen basieren und in den folgenden Abschnitten beschrieben werden.
Auswirkung auf ein verteiltes Grid
Wenn in einer Client/Server-Umgebung ein Abrufplan mit unbegrenzter Tiefe verwendet wird, werden alle Relationen, die aus Eager-Sicht über die Stammentität erreichbar sind, in einer einzigen Client/Server-Austauschoperation abgerufen.
Beispiel: Wenn die Anwendung an allen Adressentitäten (Address) aller Mitarbeiter (Employee) einer bestimmten Abteilung (Department) interessiert ist, verwendet sie einen Abrufplan mit unbegrenzter Tiefe, um alle zugeordneten Adressentitäten abzurufen. Mit dem folgenden Code findet nur eine einzige Client/Server-Austauschoperation statt:
em.getFetchPlan().setMaxFetchDepth(FetchPlan.DEPTH_INFINITE);
tran.begin();
Department dept = (Department) em.find(Department.class, "dept1");
// Address-Objekt bearbeiten
for (Employee e: dept.employees) {
for (Address addr: e.addresses) {
// Adressen bearbeiten
}
}
tran.commit();
Wenn in einer Client/Server-Umgebung ein Abrufplan mit Tiefe null verwendet wird, wird nur die Stammentität in der ersten Client/Server-Austauschoperation abgerufen. Alle Eager-Beziehungen werden als Lazy-Beziehungen behandelt.
Beispiel: In diesem Beispiel ist die Anwendung nur an der Entität "Department" interessiert. Sie muss nicht auf die Mitarbeiter der Abteilung zugreifen, und deshalb setzt die Anwendung die Abrufplantiefe auf 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");
// dept-Objekt bearbeiten
tran.commit();
Bei einem Abrufplan mit Tiefe k ist die maximale Abruftiefe auf k gesetzt.
Wenn in einer eXtreme-Scale-Client/Server-Umgebung ein Abrufplan mit Tiefe k verwendet wird, werden alle Beziehungen, die aus Eager-Sicht über die Stammentität erreichbar sind, in der ersten Client/Server-Austauschoperation in k Schritten abgerufen.
Der Abrufplan mit unbegrenzter Tiefe (k = Unendlich) und der Abrufplan mit Tiefe null (k = 0) sind nur zwei Beispiele für einen Abrufplan mit Tiefe k.
Nehmen Sie als Fortsetzung des vorherigen Beispiels an, dass es eine weitere Eager-Beziehung zwischen der Entität "Employee" und der Entität "Address" gibt. Wenn der Abrufplan eine definierte maximale Abruftiefe von 1 hat, ruft die Operation em.find(Department.class, "dept1") die Entität "Department" und alle zugehörigen Employee-Entitäten in einer einzigen Client/Server-Austauschoperation ab. Die Address-Entitäten werden jedoch nicht abgerufen, weil sie aus Eager-Sicht gesehen über die Entität "Department" nicht in einem Schritt, sondern erst in zwei Schritten erreichbar sind.
Wenn Sie einen Abrufplan mit Tiefe 2 verwenden, ruft die Operation em.find(Department.class, "dept1") die Entität "Department", alle zugehörigen Employee-Entitäten und alle Address-Entitäten, die den Employee-Entitäten zugeordnet sind, in einer einzigen Client/Server-Austauschoperation ab.
Bei der Ausführung einer Entitätsabfrage können Sie ebenfalls einen Abrufplan verwenden, um den Abruf von Beziehungen anzupassen.
Das Ergebnis der Abfrage SELECT d FROM Department d WHERE "d.deptName='Department'" enthält beispielsweise eine Beziehung zur Entität "Department". Beachten Sie, dass die Abrufplantiefe mit der Assoziation des Abfrageergebnisses beginnt: in diesem Fall mit der Entität "Department" und nicht mit dem Abfrageergebnis selbst. Das bedeutet, dass die Entität "Department" sich auf Abruftiefestufe 0 befindet. Deshalb ruft ein Abrufplan mit der maximalen Abruftiefe 1 die Entität "Department" und die zugehörigen Employee-Entitäten in einer einzigen Client/Server-Austauschoperation ab.
Beispiel: Die Abrufplantiefe wird auf 1 gesetzt, so dass die Entität "Department" und die zugehörigen Employee-Entitäten in einer einzigen Client/Server-Austauschoperation abgerufen werden. Die Address-Entitäten werden in dieser Austauschoperation jedoch nicht abgerufen.
Standardmäßig werden alle Beziehungen, die aus Eager-Sicht über die Stammentität erreichbar sind, in einer einzigen Client/Server-Autauschoperation abgerufen. Dies kann die Leistung verbessern, wenn alle Beziehungen verwendet werden. In bestimmten Einsatzszenarien werden jedoch nicht alle aus Eager-Sicht über die Stammentität erreichbaren Beziehungen verwendet. Der Abruf dieser nicht verwendeten Entitäten bedeutet also einen erhöhten Aufwand für die Laufzeitumgebung und eine Einschränkung der Bandbreite.
Für solche Fälle kann die Anwendung die maximale Abruftiefe auf einen kleineren Wert setzen, um die Tiefe der abzurufenden Entitäten zu verringern, indem alle Eager-Relationen nach dieser Tiefe als Lazy-Relationen definiert werden. Diese Einstellung kann die Leistung verbessern.
Zur weiteren Fortsetzung des vorherigen Department-Employee-Address-Beispiels werden jetzt alle Address-Entitäten, die Mitarbeitern der Abteilung "dept1" zugeordnet sind, wenn em.find(Department.class, "dept1") aufgerufen wird. Wenn die Anwendung keine Address-Entitäten verwendet, kann sie die maximale Abruftiefe auf 1 setzen, so dass die Address-Entitäten nicht zusammen mit der Entität "Department" abgerufen werden.