9

IBMは、EntityManagersを使用するためのベスト・プラクティスはget / use/closeであると提案しています。EntityManagerが閉じられていない場合、同じEntityManagerが複数のスレッドで使用され、次のエラーが発生する可能性があります。

<openjpa-2.1.2-SNAPSHOT-r422266:1179900 fatal general error> org.apache.openjpa.persistence.PersistenceException: Multiple concurrent threads attempted to access a single broker. By default brokers are not thread safe; if you require and/or intend a broker to be accessed by more than one thread, set the openjpa.Multithreaded property to true to override the default behavior. 

次のように、fetch =LAZYとしてマップされたOneToManyコレクションを持つオブジェクトをロードする場合:

public T find(Object id) {
    T t = null;
    EntityManager em = getEm();
    t = em.find(type, id);
    em.close();
    return t;
}

EntityManager getEm() {
    if(this.em ==null || !this.em.isOpen()) {
        this.em = emf.createEntityManager();            
    }
    return this.em;
}

誰かがゲッターを呼び出すまでに、EntityManagerが閉じられるため、コレクションは常にnullになります。コレクションは、フェッチがEAGERの場合にのみロードされますが、その結果、毎回SQL結合が発生し、速度が低下します。

したがって、これは「マルチスレッド」エラーか、openjpa.Multithreaded = trueのいずれかです。これは悪い習慣であるか、コレクションが必要ない場合でも毎回SQL結合があるために低速です。レイジーフェッチで高速になり、ベストプラクティスのみを使用して実行されるように、適切に実行する方法はありますか?

4

4 に答える 4

3

さて、これがこの問題に関する2日間の調査の後の私の結論です。Java EEサーバーへのデプロイに依存できず、シングルスレッドアクセスを保証できないアプリケーション(Tomcat上のWebアプリなど)の場合、ベストプラクティスは、メソッドの範囲内でエンティティマネージャーを開き、使用し、閉じることです。 DAOオブジェクトの。

これは、遅延読み込みがDAOの外部では機能しないことを意味します。これを回避するには、IDで1つのエンティティを検索するメソッドで、エンティティマネージャーを閉じる前にコレクションでsize()を呼び出してフェッチをトリガーすることにより、すべてのコレクションをフェッチする必要があります。これにより、フェッチが遅延している場合でも、findメソッドは完全にロードされたオブジェクトを返します。

検索のようにオブジェクトのコレクションを返すメソッドの場合、検索結果の各エンティティを完全にロードするには遅すぎるため、結果は子なしでそのまま返されます。検索結果のエンティティの1つを表示する必要がある場合は常に、完全にロードされたオブジェクトを取得するメソッドを介して、エンティティを個別にロードする必要があります。

于 2012-10-23T10:01:37.303 に答える
2

わかりました。JavaEEを使用せずに、EntityManagerの単純なプールを作成できます。StackKeyedObjectPool(Apache Commons Poolから)を使用し、必要なときに新しいEntityManagerを作成します。借用/返却インターフェースがあり、プールは必要に応じて新しいオブジェクトを自動的に作成します。http://commons.apache.org/pool/api-1.6/org/apache/commons/pool/impl/StackKeyedObjectPool.htmlを参照してください

于 2012-10-22T16:43:08.020 に答える
0

実際には、Websphereにエンティティマネージャーを挿入させることができるはずです。

@PersistenceContext(unitName = "<whatever>")
private EntityManager em;

データにアクセスする必要がある場所。各Beanは単一のリクエストのみを処理し、そのリクエストは単一のスレッドで処理されるため、アプリケーションサーバーがスレッドの問題を処理します。

于 2012-10-19T15:11:03.380 に答える
0

サーブレット(Tomcat)コンテナ内で自動管理されたEntityManagerの有効期間を提供するGitHubプロジェクトを作成しました。シングルスレッドのhttpリクエストコンテキストは同じインスタンスを取得し、EMはhttpリクエストの終了時に自動的に閉じられます。これにより、明示的なtry-catch-finallyボイラープレートを使用せずに、サーブレットおよびjspスクリプトを簡単に抽象化できます。
https://github.com/Murmur/ScopedEntityManager

于 2014-07-22T19:58:20.670 に答える