1. ホーム
  2. java

[解決済み] JPA Entity Managerは閉鎖されるべきか?

2023-04-15 20:04:27

質問

以下のようなメソッドを持っています。

public Profile readUser(String email){
    EntityManager em = EMF.get().createEntityManager();
    return em.find(Profile.class, email);
}

エンティティマネージャーの使い方は上記の通りでよいのでしょうか?それとも、閉じる必要があるのでしょうか?

どのように解決するのですか?

答えはこうでしょう。 それは依存します。 .

エンティティマネージャは、エンティティが存在するコンテキストにアクセスするための鍵です。もしあなたのアプリケーションが日本証券業協会のアプリケーションであれば、コンテキストの寿命がどれくらいかを考慮しなければなりません。

ユーザーのリクエストごとにエンティティマネージャーを作成することを考えましょう。そこで、あるリクエストに対応している間は、エンティティマネージャーを開いたままにしておき、それが終わったら閉じます。

日本証券業協会のアプリケーションでは、アプリケーションの全期間中(大量のデータを扱わないと仮定して)エンティティ・マネージャーを開いておき、アプリケーションがシャットダウンしたときに閉じることを考えたかもしれません。

結論として、いつ開き、いつ閉じるかは、あなたの戦略と設計に完全に依存します。そのコンテキストでエンティティをもはや必要としないとき、それを閉じます。

あなたの例では、それは明らかではありませんが、メソッド内でEMを作成しているので、戻る前にそれを閉じるべきです。そうでなければ、もはやそれに再びアクセスすることはできません(コードでは明らかではありませんが、何らかのレジストリにそれを保持していない限り)。

もしクローズしなければ、エンティティは使い終わった後でもアタッチされたままです。コンテキストは、EM にもはやアクセスできないときでも、生き続けます。

その JPA仕様 にはより詳細な情報が含まれています。セクション中の 7.7 アプリケーションが管理する永続性コンテクスト と書いてあります。

アプリケーションで管理されるエンティティ・マネージャが使用される場合、アプリケーションは 永続化プロバイダのエンティティ・マネージャと直接対話します。 ファクトリーと直接対話し、エンティティ・マネージャーのライフサイクルを管理し、永続化コンテキストを取得および破棄します。 永続化コンテキストを破棄します。

このようなアプリケーションで管理される永続性コンテキストはすべて、スコープが拡張され スコープで拡張され、複数のトランザクションにまたがることができます。

EntityManagerFactory.createEntityManager メソッドと EntityManager close そして isOpen メソッドを使用します。 メソッドは、アプリケーションで管理されるエンティティ・マネージャとそれに関連する のライフサイクルを管理するために使用されます。

拡張された永続性コンテキストは を使用してエンティティ・マネージャが作成された時点から存在します。 EntityManagerFactory.createEntityManager を使って作成された時点から、エンティティ・マネージャが によって閉じられるまで存在します。 EntityManager.close .

アプリケーションによって管理されるエンティティ・マネージャから取得される拡張永続性コンテキストは、独立した永続性コンテキストです。 エンティティマネージャから取得した拡張永続化コンテキストは、スタンドアロン永続化コンテキストであり、トランザクションと共に伝搬されません。 トランザクションと一緒に伝搬されません。

[...] アプリケーションが管理する EntityManager.close メソッドはエンティティ・マネージャーを閉じて その永続性コンテキストと他のリソースを解放します。closeを呼び出した後 を呼び出した後、アプリケーションはそれ以上 EntityManager インスタンスに対してそれ以上メソッドを呼び出してはいけません。 getTransactionisOpen または は IllegalStateException が投げられます。トランザクションがアクティブなときにcloseメソッドが呼び出された場合 メソッドが呼び出された場合、トランザクションが完了するまで永続化コンテキストは はトランザクションが完了するまで管理されます。

EntityManager.isOpen メソッドは、エンティティ・マネージャが が開かれているかどうかを示します。このメソッドは isOpen メソッドは、エンティティ・マネージャが閉じられるまで真を返します。 を返します。 これがどのように動作するかを実際に理解するためには、エンティティ・マネージャとコンテキストの関係を理解することが不可欠です。

エンティティマネージャはエンティティにアクセスするためのパブリックインタフェースですが、エンティティはエンティティマネージャに接続されたコンテキストに存在します。異なるタイプのコンテキストのライフサイクルを理解することで、あなたの質問に答えることができます。

永続化コンテキストには、さまざまなタイプがあります。Java EEアプリケーションでは、1つのコンテクストに対して トランザクション・スコープの永続性コンテキスト または 拡張パーシステンスコンテキスト . JSEアプリケーションでは、コンテキストの性質は 開発元が管理する .

エンティティマネージャにエンティティを要求すると、そのエンティティが添付されているコンテキストでエンティティを探し、そこでエンティティが見つかればそれを返し、そうでなければデータベースからエンティティを取り出します。それ以降、このエンティティをコンテキストで呼び出すと、同じエンティティが返されます。

トランザクションスコープ

トランザクションスコープの永続化コンテキストを使用するJava EEアプリケーションでは、最初にエンティティマネージャにアクセスするとき、現在のJTAトランザクションにコンテキストがあるかどうかをチェックします。コンテキストがまだ存在しない場合、新しいコンテキストが作成され、エンティティマネージャはこのコンテキストにリンクされます。そして、エンティティがデータベースから読み込まれ(キャッシュがあればそこから)、コンテキストに配置されます。トランザクションが終了すると(コミットまたはロールバック)、コンテキストは無効となり、その中のエンティティはすべて切り離される。これはステートレスセッションBeanの古典的なシナリオである。

@PersistenceContext(unitName="EmplService")
EntityManager em;

これはまた、トランザクションをどのように設計するかによって、複数のコンテキストを持つことになる可能性があることを意味します。

拡張パーシステンスコンテキスト

ステートフルセッションBeanを使用するJava EEアプリケーションでは、Beanが削除されるまでコミットしたくないので、コンテキストが複数のBeanの起動に耐えられるようにしたいかもしれませんね?そのような場合、拡張永続化コンテキストを使用する必要があります。この場合、永続化コンテキストは最初に必要になったときに作成されますが、ステートフルBeanを削除するためにマークするまで無効にはなりません。

@PersistenceContext(unitName="EmplService", type=PersistenceContextType.EXTENDED)

これは、ステートフルセッションビーンズのメソッドのその後の呼び出しで、このビーンに注入されるエンティティマネージャーのインスタンスに関係なく、常に同じコンテキストにアクセスすることを保証し、したがって、その後の呼び出しでも、同じインスタンスが返されることを意味する。

また、Beanが削除されるようにマークされるか、手動でフラッシュするまで、変更内容はフラッシュされることはありません。

アプリケーション管理型

エンティティマネージャーファクトリーとエンティティマネージャーを常に手動でインスタンス化することができます。これは、JSEアプリケーションで一般的に行うことですが、正しいですか?

この種のアプリケーションでは、通常、JTAトランザクションを処理するコンテナがありませんよね?そのため、リソースローカルなトランザクションを使用し、手動で変更をコミットまたはロールバックする責任を負います。

この種のアプリケーションでは、エンティティ・マネージャーをインスタンス化するときに、コンテキストが自動的にアタッチされます。

アプリケーションによっては、ライフサイクルがアプリケーション自体のライフサイクルに付随するグローバルエンティティマネージャを作成することを決定することができます。これは、アプリケーションの全ライフサイクルに対する単一のエンティティマネージャです。この場合、コンテキストはエンティティマネージャと一緒に作成され、破棄されます。

または、アプリケーションのユーザーとの会話(つまりトランザクション)ごとにエンティティマネージャーを作成することもできます。この場合、スコープはあなたによって決定されますが、それでも、あなたのコンテキストは、あなたのエンティティマネージャで作成され、破棄されるでしょう。