EJB 3.0(Public Draft)入門記 Java Persistence API Chapter5 その4

ひさびさの入門記。ワンダと巨像とか麻雀とかに興じていたら書かないことになれちゃいました、やばいやばい。

今回は永続コンテキスト(persistence context)についてです。

5.4 Persistence Contexts

永続コンテキストの定義は何回も出てきているのですが、超訳するとこんな感じになります(関係代名詞あたりがうまく訳せないのであくまで超訳)。

永続コンテキストとはエンティティのインスタンスの集合である。その集合は一意なエンティティのインスタンスで構成される。各インスタンスは永続エンティティIDをもつ。

永続エンティティID(persistent entity identity)って@Idで指定するID、すなわちデータベースのプライマリキーだと思います。

永続コンテキストには4種類あります。

  • Container-managed Transaction-scoped Persistence Context
  • Container-managed Extended Persistence Context
  • Application-managed Transaction-scoped Persistence Context
  • Application-managed Extended Persistence Context

永続コンテキストのライフサイクルをコンテナ任せにするかアプリケーションで明示的に指示するのかでコンテナ管理とアプリケーション管理に分かれます。これはEJBを使うかどうかには関係ないようです。次にトランザクションスコープの永続コンテキストか拡張された永続コンテキストかで2つにわかれます。

5.4.1 Container-managed Persistence Contexts

まずコンテナ管理の永続コンテキストについて。

コンテナ管理の永続コンテキストは常にコンテナ管理のEntityManagerに関連づいているそうです。永続コンテキストのライフサイクルは自動的にコンテナに管理されます。EntityManagerのcloseは必要ないということですね。

永続コンテキストとEntityManagerの関係はというと、永続コンテキストにアクセスしてエンティティをアプリケーションに受け渡しするのがEntityManagerです。

5.4.1.1 Container-managed Transaction-scoped Persistence Context
コンテナ管理のトランザクションスコープな永続コンテキストの説明です。一番シンプルで通常もっともよく使われるタイプだと思います。

永続コンテキストの開始と終了は次のように行われるそうです。

  • 永続コンテキストの開始
  • 永続コンテキストの終了
    • JTAトランザクションが完了した場合に永続コンテキストが終了し、EntityManagerに管理されたすべてのエンティティが切り離されます。

EntityManagerがトランザクションのスコープ外で呼び出された場合、呼び出されたEntityManagerのメソッド実行のためだけに永続コンテキストが作成と破棄が行われ、データベースからロードされたエンティティはメソッド呼び出しの終了時にすみやかに切り離されるそうです。
EntityManagerのfindとかcreateQueryなどのメソッドはトランザクション実行中じゃなくても呼べるようなので、そういうメソッドを呼び出したときの話なんだ思います。でもJTAトランザクションが実行されていないのにEntityManagerを呼び出すときってどんなとき?。

5.4.1.2 Container-managed Extended Persistence Context
コンテナ管理の拡張された永続コンテキストの説明です。

拡張永続コンテキストはコンテナ管理のEntityManagerがDIやlookupで取得されてからコンテナによってcloseされるまで存在するそうです。拡張永続コンテキストはステートフルセッションBean内でのみ使用可能というのがポイント。拡張永続コンテキストは、@Removeつきのメソッドが呼び出されるなどステートフルセッションBeanが終了するときにcloseされます。
拡張永続コンテキストが使われると、EntityManagerに管理されたエンティティはトランザクションのコミット後も管理され続け、永続コンテキストが終了するまで切り離されません。

拡張永続コンテキストはアプリケーショントランザクション(ロングトランザクション)を実現するために便利なように作ってあるというフレコミですが、これを使うかどうかは人によって意見が分かれそうです。理由は次回(たぶん)。

5.4.2 Application-managed Persistence Contexts

次にアプリケーション管理の永続コンテキストについて。

アプリケーション管理の永続コンテキストは常にアプリケーション管理のEntityManagerに関連づいているそうです。永続コンテキスト(というか永続コンテキストに関連付けられたEntityManager)の取得と破棄はアプリケーションが行う必要があります。取得と破棄はそれぞれ次のように行います。

  • EntityManagerFactory.createEntityManager()
  • EntityManager.close()

トランザクションJTAトランザクションとリソーストランザクションどちらでも使えるみたいす。

5.4.2.1 Application-managed Transaction-scoped Persistence Context
アプリケーション管理のトランザクションスコープな永続コンテキストの説明です。

5.4.2.2 Application-managed Extended Persistence Context
アプリケーション管理の拡張された永続コンテキストの説明です。

EntityManagerFactory.createEntityManager()で永続コンテキストを開始してEntityManager.close()で終了するまでトランザクションをコミットしてもEntityManagerに管理されたエンティティは管理され続けます。永続コンテキストが終了するまで切り離されません。

5.4.3 Persistence Context Propagation

コンテナ管理の永続コンテキストでは、1つの永続コンテキストが1つ以上のJTA EntityManagerのインスタンスに対応します。アプリケーション管理の永続コンテキストには永続コンテキストの伝播は適用されないそうです。

ルールを箇条書きにすると次のようになります。

  • コンテナ管理のトランザクションスコープの永続コンテキストを使った場合、JTAトランザクションの伝播により同じトランザクションコンテキストにアクセスするEntityManagerをまたがって永続コンテキストの伝播が起こる
  • 異なるJTAトランザクションに属するEntityManagerは同じ永続コンテキストを共有しない
  • 異なったEntityManagerFactoryから取得されたEntityManagerは決して同じ永続コンテキストを共有しない

特に覚えにくいところはないかんじ。

5.4.3.1 Persistence Context Propagation for Transaction-scoped Persistence Contexts
アプリケーションはJTA EntityManagerをDIなどで取得できますが、そのEntityManagerはJTAトランザクションに関連付けられた永続コンテキストにアクセスします。
永続コンテキストの伝播は次のルールに従うようです。

  • JTAトランザクションが実行されていないときにEntityManagerが呼び出された場合、呼び出されたEntityManagerのメソッド実行のためだけに永続コンテキストの作成と破棄が行われ、データベースからロードされたエンティティはメソッド呼び出しの終了時にすみやかに切り離される。
  • EntityManagerが呼び出されたが現在のJTAトランザクションに関連付けられた永続コンテキストがまだ存在しない場合、新しい永続コンテキストが作成されてJTAトランザクションに関連付けられる。メソッドの呼び出しはこのコンテキスト内で実行される。
  • EntityManagerが呼び出されて現在のJTAトランザクションに関連付けられた永続コンテキストがすでに存在する場合、メソッドの呼び出しはこのコンテキスト内で行われる。

ここも特に覚えにくいところはないかんじ。
JTAトランザクションが実行されていないときのEntityManagerの呼び出しは気になりますが...

5.4.3.2 Persistence Context Propagation Rules for Extended Persistence Contexts
EntityManagerの永続コンテキストタイプが拡張永続コンテキストである場合、次のルールが適用されるそうです。

  • トランザクションスコープの永続コンテキストをもったコンポーネントが拡張永続コンテキストをもったステートフルセッションBeanを同一JTAトランザクションで呼び出した場合、IllegalStateExceptionがスローされる。
  • 拡張永続コンテキストをもったステートフルセッションBeanがトランザクションスコープの永続コンテキストをもったステートレス/ステートフルセッションBeanを同一JTAトランザクションで呼び出した場合、永続コンテキストは伝播される。
  • 拡張永続コンテキストをもったステートフルセッションBeanがトランザクションスコープの永続コンテキストをもったステートレス/ステートフルセッションBeanを異なったJTAトランザクションで呼び出した場合、永続コンテキストは伝播されない。
  • 拡張永続コンテキストをもったステートフルセッションBeanがもうひとつの拡張永続コンテキストをもったステートフルセッションBeanをインスタンス化した場合、拡張永続コンテキストは2つ目のステートフルセッションBeanに継承される。2つ目のステートフルセッションBeanが1つ目のステートフルセッションBeanと異なったトランザクションコンテキストで呼び出された場合、IllegalStateExceptionがスローされる。
  • 拡張永続コンテキストをもったステートフルセッションBeanが異なった拡張永続コンテキストをもったステートフルセッションBeanを同一トランザクションで呼び出した場合、IllegalStateExceptionがスローされる。

すっと頭に入るの1番目と2番目くらいなんですけど...、拡張永続コンテキスト(というかステートフルセッションBeanのせい?)は考慮点が多いですね。使うのならばちゃんと理解しておかないとハマりそうです。

今回はだらだらとドキュメントの内容を書いて(誤訳?して)みました。次回は拡張永続コンテキストを使ったコードを動かしてみたいと思います。