アプリケーション管理エンティティーマネージャー | コンテナ管理エンティティーマネージャー |
エンティティーマネージャーインスタンスの取得は、エンティティーマネージャーファクトリを使って指定 | エンティティーマネージャーインスタンスの取得は、@PersistenceContext 注釈または JNDI ルックアップを使って指定 |
拡張スコープの持続性コンテキストが必須 | トランザクションスコープの持続性コンテキストが必須 |
アプリケーション管理トランザクションが必須 | アプリケーション管理トランザクションが必須 |
@PersistenceUnit(unitName="CatalogPu") EntityManagerFactory emf
です。コードは、そのエンティティーマネージャーを使い終わるまでファクトリを保持して、再利用できるようにします。EntityManagerFactory はスレッドセーフなアプリケーションスコープで保持できるため、アプリケーション管理エンティティーマネージャーを使った Web 専用アプリケーションでは、アプリケーションスコープで EntityManagerFactory をキャッシュし、要求間で共有されるようにします。アプリケーションがエンティティーマネージャーファクトリを閉じると、そのすべてのエンティティーマネージャーが閉じた状態であるとみなされます。EntityManager em = emf.createEntityManager()
への呼び出しでエンティティーマネージャーを取得することで指定します。
これで、エンティティーマネージャー API を使用して、エンティティーを持続させたり、エンティティーに問い合わせたりできます。@PersistenceUnit private EntityManagerFactory emf;
//再利用するためインスタンス変数として宣言。
...
//このメソッドはエンティティーマネージャーを使ってエンティティー Item.java を持続させる
public void addItem(Item item){
EntityManager em = emf.createEntityManager();
try {
...
em.persist(item);
...
} finally {
em.close();
}
close
、isOpen
、および joinTransaction
メソッドを使って、エンティティーマネージャーとそのライフサイクルを管理します。また、アプリケーションは、使い終えた時にエンティティーマネージャーを閉じる必要があります。EntityManager はスレッドセーフではないため、スレッドセーフではない方法で EntityManager のインスタンスに対する参照を保持してはいけません。
アプリケーション管理エンティティーマネージャーは拡張スコープの持続性コンテキストを持つため、複数の要求に対して同じエンティティーマネージャーを開いたままにし、処理が終了した時点でそのエンティティーマネージャーを閉じることができます。アプリケーション管理エンティティーマネージャーはまた、トランザクションスコープのエンティティーマネージャーの振る舞いを真似ることができ、それを作成した同じメソッドの終了時にエンティティーマネージャーを閉じることができます。このようにして、拡張スコープの持続性コンテキストは、トランザクションスコープの持続性コンテキストの振る舞いを実現したり、複数の HTTP 要求、複数のトランザクションにまたがることができるため、自由度の面で優れています。エンティティーマネージャーを開いたままにして、拡張スコープの持続性コンテキストを利用するケースとしては、いくつかのフォーム送信を使ってエンティティー内のすべてのユーザー情報を収集する複数ページからなるフォームがあります。ユーザー情報の収集を終えたあと、すべてのエンティティーをフラッシュし、それらエンティティーをデータベースに送信できます。javax.persistence.EntityManager
インタフェース内のメソッドには、トランザクションコンテキスト内での呼び出し必要とするものがあります。トランザクションがなく持続性コンテキストがトランザクションスコープの場合、そうしたメソッドは TransactionRequiredException
をスローします。データベースにデータを書き込んだり、データを更新したりします。そうしたメソッドを呼び出す前には、トランザクションコンテキストが存在することを事前に確認する必要があります。
persist
、merge
、remove
、flush
、および refresh
メソッドがこれに該当します。
JTA エンティティーマネージャーのコード | リソースにローカルのエンティティーマネージャーのコード |
@PersistenceUnit EntityManagerFactory emf; |
@PersistenceUnit private EntityManagerFactory emf; ... |
悪い例: スレッドセーフでないため、良くない |
良い例: スレッドセーフ。 注釈を使用して、最初に JNDI 依存性を宣言。JNDI ルックアップを使用して、エンティティーマネージャーを取得。 |
public class MyServlet extends HttpServelet {
@PersistenceContext EntityManager em; public void doGet( HttpServletRequest req,
... em.persist(item) ....エンティティーマネージャーを使用するコードが続く } |
また、JNDI ルックアップでの em 取得にも注目 ....エンティティーマネージャーを使用するコードが続く } |
@PersistenceContext(name="foo", unitName="myPuName")
public class MyServlet extends HttpServelet {
@Resource UserTransaction utx;
public void doGet(HttpServletRequest req,
HttpServletResponse resp) throws throws ServletException, IOException {
EntityManager em = (EntityManager) ic.lookup("java:comp/env/foo");
//要求からデータを取得
String name = request.getParameter("item_name");
...
//新規 Item エンティティーを作成
Item item = new Item();
//Item エンティティーの値を設定
item.setName(name);
...
utx.begin();
em.persist(item); //新規 Item を持続させ、データベースに追加
utx.commit();
...
}
@Resource
注釈によって、JTA トランザクションを制御するための UserTransaction インスタンスを注入します。UserTransaction はスレッドセーフであるため、ほかの要求と共有されるインスタンス変数として保持できます。ここではデータベース書き込みを行うため、em.persist()
を呼び出す直前にトランザクションを開始し、あとでコミットします。コンテナはこのエンティティーマネージャーのライフサイクルを管理し、メソッドの最後で閉じます。サーブレットクラスに、持続性コンテキストで依存性を宣言するための @PersistenceContext(name="foo", unitName="myPuName")
注釈があることに注目してください。このあと、Servlet.doGet メソッド内で JNDI を使ってエンティティーマネージャーをルックアップし、取得しています (EntityManager em = ic.lookup("java:comp/env/foo"))
。