JPA Entity Managerを閉じる必要がありますか?


82

以下の方法があります。

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

上記のエンティティマネージャの使用法は大丈夫ですか?またはemを閉じる必要がありますか?何か提案がありますか?



いいえ、ただいいえ。あなたがリークをしたい場合を除き...

回答:


131

私は答えが次のとおりと思います:それは依存します

エンティティマネージャは、エンティティが存在するコンテキストにアクセスするための鍵です。アプリケーションがJSEアプリケーションの場合、コンテキストの平均余命を考慮する必要があります。

ユーザーの要求ごとにエンティティマネージャーを作成するとします。したがって、特定のリクエストに参加している間は、エンティティマネージャを開いたままにし、それが終了したら閉じます。

JSEアプリケーションでは、エンティティマネージャーをアプリケーションの存続期間中ずっと開いたままにしておき(大量のデータを処理していないと仮定して)、アプリケーションがシャットダウンしたときに閉じることを検討したかもしれません。

結論として、いつ開くか、いつ閉じるかは、戦略と設計に完全に依存します。コンテキスト内のエンティティが不要になったら閉じます。

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

閉じないと、使用が終了した後でも、エンティティはアタッチされたままになります。EMにアクセスできなくなった場合でも、コンテキストは存続します。

JPA仕様の詳細が含まれています。セクション7.7アプリケーション管理の永続性コンテキストでは、次のように述べています。

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

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

EntityManagerFactory.createEntityManager方法と EntityManager closeし、isOpen方法は、アプリケーション管理エンティティマネージャとその関連する永続コンテキストのライフサイクルを管理するために使用されます。

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

アプリケーション管理のエンティティマネージャから取得された拡張永続コンテキストは、トランザクションとともに伝播されないスタンドアロンの永続コンテキストです。

[...]このEntityManager.closeメソッドは、エンティティマネージャーを閉じて、永続コンテキストとその他のリソースを解放します。closeを呼び出した後、アプリケーションはEntityManagergetTransactionand isOpen、またはを除いて、インスタンスでそれ以上のメソッドを呼び出さないでください。 IllegalStateExceptionがスローされます。トランザクションがアクティブなときにcloseメソッドが呼び出された場合、永続コンテキストはトランザクションが完了するまで管理されたままになります。

このEntityManager.isOpenメソッドは、エンティティマネージャが開いているかどうかを示します。このisOpenメソッドは、エンティティマネージャが閉じられるまでtrueを返します。これがどのように機能するかを実際に理解するには、エンティティマネージャとコンテキストの関係を理解することが重要です。

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

永続コンテキストにはさまざまなタイプがあります。Java EEアプリケーションでは、トランザクションスコープの永続コンテキストまたは拡張永続コンテキストのいずれかを使用できます。JSEアプリケーションでは、コンテキストの性質は開発者によって制御されますます。

エンティティマネージャにエンティティを要求すると、アタッチされたコンテキストでエンティティが検索され、そこでエンティティが見つかった場合はそれが返されます。それ以外の場合は、データベースからエンティティが取得されます。コンテキスト内でこのエンティティを後で呼び出すと、同じエンティティが返されます。

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

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

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

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

拡張永続コンテキスト

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

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

つまり、ステートフルセッションBeanメソッドの後続の呼び出しでこのBeanに注入されるエンティティマネージャーのインスタンスに関係なく、常に同じコンテキストにアクセスできるため、後続の呼び出しでも同じコンテキストが返されます。インスタンス、同じコンテキストであるため。

また、Beanに削除のマークが付けられるか、手動でフラッシュするまで、変更はフラッシュされません。

アプリケーション管理

エンティティマネージャファクトリとエンティティマネージャはいつでも手動でインスタンス化できます。これは、JSEアプリケーションで通常行うことですが、そうですか?

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

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

アプリケーションに応じて、ライフサイクルがアプリケーション自体のライフサイクルに関連付けられているグローバルエンティティマネージャーを作成することを決定できます。これは、アプリケーションの存続期間全体にわたって単一のエンティティマネージャーです。この場合、コンテキストはエンティティマネージャで作成および破棄されます。

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


すばらしい答えですが、知っておく必要があります。セッション中にEntityManagerを数回開いたり閉じたりすると、パフォーマンスに高いコストがかかりますか?一度だけインスタンス化して閉じるか、それともすべてのデータベースのクラッド操作でインスタンス化/使用/閉じるか、どちらが最善のアプローチですか?... OK「それが依存」が、ユースケースの大多数のためのより適切な使用を持っている必要があります
tomrlh

4
@tomurlh私に関する限り、作成のコストはEntityManagerごくわずかでなければなりません。私の見解では、EntityManagerは、現在のトランザクションの作業単位を処理するための単なる抽象化です。トランザクションごとに1つ作成して破棄することはまったく問題ないと思います。EntityManagerサーバーはエンティティのトランザクションキャッシュとして機能するため、トランザクションスコープが明確に定義されており、エンティティを適切に処理することで、このキャッシュを利用できる可能性があるため、他にも影響があります。
Edwin Dalorzo 2018

EntityManager.closeメソッドは、エンティティマネージャを閉じて、永続コンテキストを解放します。永続コンテキストとは何ですか。
gstackoverflow

これは、トランザクションの設計方法によっては、複数のコンテキストになってしまう可能性があることも意味します。 方法を説明していただけますか?
gstackoverflow
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.