FetchPlan は、アプリケーションがリレーションシップにアクセスする必要がある場合、関連付けられたオブジェクトを取得するためにエンティティー・マネージャーが使用するストラテジーです。
例えば、ご使用のアプリケーションに Department と Employee の 2 つのエンティティーがあるとします。Department エンティティーと Employee エンティティーの間のリレーションシップは、双方向の 1 対多のリレーションシップです。1 つの部門には多くの従業員がいますが、1 人の従業員は 1 つの部門にのみ属します。 Department エンティティーがフェッチされると、ほとんどの場合その部門の従業員もフェッチされるため、この 1 対多のリレーションシップのフェッチ・タイプは EAGER に設定されます。
以下に 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;
}
分散環境では、アプリケーションが em.find(Department.class, "dept1") を呼び出して Department エンティティーをキー「dept1」で検索すると、この検索操作によって Department エンティティーとその Department の EAGER フェッチの関係すべてが取得されます。 上記のスニペットの場合、これは部門「dept1」のすべての従業員です。
WebSphere® eXtreme Scale 6.1.0.5 より前では、クライアントは 1 回のクライアント/サーバー・トリップで 1 個のエンティティーを取得したので、1 個の Department エンティティーと N 個の Employee エンティティーを取得するために、N + 1 回のクライアント/ サーバー・トリップが行われました。この N + 1 個のエンティティーを 1 回のトリップで取得すれば、パフォーマンスを改善できます。
フェッチ・プランを使用すると、リレーションシップの最大項目数をカスタマイズすることによって、EAGER リレーションシップをフェッチする方法をカスタマイズすることができます。 フェッチの項目数は、LAZY 関係に指定された項目数よりも多い EAGER 関係をオーバーライドします。 デフォルトでは、EAGER 関係のフェッチの項目数がフェッチの最大項目数です。 つまり、ルート・エンティティーからナビゲート可能な EAGER である、すべてのレベルの EAGER リレーションシップがフェッチされます。 EAGER リレーションシップは、そのルート・エンティティーから始まるすべてのリレーションシップが EAGER フェッチとして構成される場合、かつこの場合に限り、ルート・エンティティーからナビゲート可能な EAGER です。
前記の例では、Department と Employee のリレーションシップは EAGER フェッチとして構成されるため、Employee エンティティーは Department エンティティーからナビゲート可能な EAGER です。
Employee エンティティーに別の、例えば Address エンティティーへの EAGER リレーションシップがある場合は、Address エンティティーも Department エンティティーからナビゲート可能な EAGER です。 ただし、Department と Employee のリレーションシップが LAZY フェッチとして構成されていた場合は、Address エンティティーは Department エンティティーからナビゲート可能な EAGER ではありません。Department と Employee のリレーションシップが EAGER フェッチ・チェーンを断ち切るからです。
FetchPlan オブジェクトは EntityManager インスタンスから取得できます。 アプリケーションは setMaxFetchDepth メソッドを使用して、フェッチの最大項目数を変更します。
フェッチ・プランは EntityManager インスタンスに関連付けられています。 フェッチ・プランはどのフェッチ操作にも適用されますが、より厳密には次のとおりです。
FetchPlan オブジェクトは可変です。 一度変更すると、後で実行されるフェッチ操作には変更された値が適用されます。
フェッチ・プランによって、EAGER フェッチのリレーションシップのエンティティーをルート・エンティティーを使用して取得するのに 1 回のクライアント/サーバー・トリップで行うのか、または複数回で行うのかが決まるため、フェッチ・プランは分散デプロイメントにとって重要です。
引き続き前述の例において、フェッチ・プランは最大項目数が無限大に設定されている、とさらに考えてみてください。 この場合、アプリケーションが em.find(Department.class, "dept1") を呼び出して Department を検索すると、この検索操作によって 1 個の Department エンティティーと N 個の従業員エンティティーが 1 回のクライアント/サーバー・トリップで取得されます。 ただし、フェッチの最大項目数がゼロに設定されているフェッチ・プランの場合は、Department オブジェクトのみがサーバーから取得されますが、Department オブジェクトの従業員集合がアクセスされるときのみ Employee エンティティーはサーバーから取得されます。
要件に基づいていくつかの異なるフェッチ・プランがあります。以下のセクションで説明します。
分散グリッドへの影響
クライアント/サーバー環境で項目数無限のフェッチ・プランを使用すると、ルート・エンティティーからナビゲート可能な EAGER であるすべての関係は、1 回のクライアント/サーバー・トリップで取得されます。
例: アプリケーションが、特定の Department の全従業員のすべての Address エンティティーに関係している場合、項目数無限のフェッチ・プランを使用して、すべての関連付けられた Address エンティティーを取得します。 以下のコードでは、1 回のクライアント/サーバー・トリップのみが行われます。
em.getFetchPlan().setMaxFetchDepth(FetchPlan.DEPTH_INFINITE);
tran.begin();
Department dept = (Department) em.find(Department.class, "dept1");
// do something with Address object.
for (Employee e: dept.employees) {
for (Address addr: e.addresses) {
// do something with addresses.
}
}
tran.commit();
クライアント/サーバー環境でゼロのフェッチ・プランを使用すると、ルート・エンティティーのみが最初のクライアント/サーバー・トリップで取得されます。 すべての EAGER リレーションシップは LAZY であるかのように扱われます。
例: この例では、アプリケーションは Department エンティティー属性にのみ関係します。その部門の従業員にアクセスする必要はないため、アプリケーションはフェッチ・プランの項目数をゼロに設定します。
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");
// do something with dept object.
tran.commit();
項目数 k のフェッチ・プランでは、フェッチの最大項目数は k に設定されています。
クライアント/サーバー eXtreme Scale 環境で項目数 k のフェッチ・プランを使用すると、k ステップ以内でルート・エンティティーからナビゲート可能な EAGER リレーションシップすべてが最初のクライアント/サーバー・トリップで取得されます。
項目数無限のフェッチ・プラン (k = 無限大) および項目数ゼロのフェッチ・プラン (k = 0) は、項目数 k のフェッチ・プランの 2 つの例にすぎません。
前述の例でさらに詳しい説明を続けるため、エンティティー Employee からエンティティー Address へ別の EAGER リレーションシップがあるとします。 フェッチ・プランで、フェッチの最大項目数が 1 に設定されていると、em.find(Department.class, "dept1") 操作によって、1 回のクライアント/サーバー・トリップで Department エンティティーおよびその Department のすべての Employee エンティティーが取得されます。 ただし、Address エンティティーは Department エンティティーへは 1 ステップ以内ではなく 2 ステップ以内でナビゲート可能な EAGER のため、取得されません。
項目数が 2 に設定されたフェッチ・プランを使用すると、em.find(Department.class, "dept1") 操作によって、1 回のクライアント/サーバー・トリップで Department エンティティー、その Department のすべての Employee エンティティー、および Employee に関連付けられたすべての Address エンティティーが取得されます。
エンティティー照会を実行する場合も、フェッチ・プランを使用してリレーションシップの取得をカスタマイズすることができます。
例えば、照会 SELECT d FROM Department d WHERE "d.deptName='Department'" の結果には、Department エンティティーへのリレーションシップがあります。 フェッチ・プランの項目数が照会結果のアソシエーションから始まることに注意してください。この場合は、照会結果そのものではなく、Department エンティティーです。つまり、Department エンティティーのフェッチの項目数はレベル 0 です。このため、フェッチの最大項目数が 1 のフェッチ・プランは、1 回のクライアント/サーバー・トリップで Department エンティティーおよびその Department の Employee エンティティーを取得します。
例: この例では、フェッチ・プランの項目数は 1 に設定されているため、Department エンティティーおよびその Department の Employee エンティティーは 1 回のクライアント/サーバー・トリップで取得されますが、Address エンティティーは同じトリップでは取得されません。
デフォルトでは、ルート・エンティティーからナビゲート可能な EAGER であるすべてのリレーションシップが 1 回のクライアント/サーバー・トリップで取得されます。 これにより、すべてのリレーションシップを使用する予定がある場合は、パフォーマンスを改善することができます。 ただし、ある種の使用に関するシナリオにおいては、ルート・エンティティーからナビゲート可能な EAGER リレーションシップがすべて使用されるとは限らないため、その未使用エンティティーを取得することによってランタイム・オーバーヘッドと処理能力オーバーヘッドがかかります。
そのような場合に、アプリケーションはフェッチの最大項目数を小さな数に設定し、その特定の項目数の LAZY の後ですべての EAGER 関係を作成することで取得するエンティティーの項目数を減らすことができます。 この設定により、パフォーマンスを改善することができます。
前出の Department と Employee と Address の例をさらに続けると、デフォルトで、Department 「dept1」の従業員に関連付けられたすべての Address エンティティーは、em.find(Department.class, "dept1") が呼び出される場合に取得されます。 アプリケーションが Address エンティティーを使用しない場合は、フェッチの最大項目数を 1 に設定することも考えられるため、Address エンティティーは Department エンティティーと一緒には取得されません。