9

Bean を構築した後、EntityManager を使用してデータベースからデータを取得したいと考えています。コンストラクターが呼び出された後に EntityManager が注入されるため、コンストラクターでは不可能です。だから私は @PostConstruct で注釈を付けたメソッドでそれをやろうとしました。API によると、PostConstruct メソッドは、すべての注入が完了した後に呼び出されます。クエリを実行すると機能しますが、常に空のリストが返されます。他のメソッドで同じクエリを使用すると、正しい結果が返されます。PostConstruct メソッドで機能しない理由を知っている人はいますか?

@Stateful(mappedName = "price")
@Singleton
@Startup
public class PriceManagementBean implements PriceManagement {

    @PersistenceContext
    private EntityManager em;

    private List<PriceStep> priceSteps =  Collections.synchronizedList(new ArrayList<PriceStep>());


    public PriceManagementBean(){


    }


    @PostConstruct
    public void init(){
        javax.persistence.Query query = em.createQuery("SELECT ps FROM PriceStep ps");
        List<PriceStep> res = query.getResultList();
            .....
       }
}
4

2 に答える 2

9

PostConstruct メソッドで機能しない理由を知っている人はいますか?

理由 1 @Stateful と @Singleton を同時に持つ Bean を作成することはできません (できますが、Singleton も Stateful であるため意味がありません)。これが、問題が発生している理由の 1 つです。例外はありませんが、競合があります。最初にそれを修正する必要があります。

覚えとけ:

  • Singleton Bean は、その状態を維持する Bean です。アプリケーションには Singleton のインスタンスが 1 つしかなく、アプリケーションのすべてのユーザー間で共有されます。また、これは共有 (コンカレントと言ったほうがよいかもしれません) Bean であるため、@Lock アノテーションを使用してある種のロック メカニズムを実装する必要があります。

  • ステートフル Bean は、トランザクション後に各状態を管理する Bean です。ステートフル Bean を使用する場合
    、各ユーザーは、セッションの間、または @Remove で注釈が付けられたメソッドが呼び出されるまで続く Bean のコピーを取得します。

理由 2機能しても、メソッドinit() 内からのみアクセスできる res というオブジェクトに結果を格納しているため、結果にアクセスできません。その戻り値を変数priceStepsに割り当てたいと思います。

とにかく、すべてを言っているわけではないため、コードには多くの問題があります。システム要件はわかりませんが、データベースにアクセスできるようにする簡単なソリューションを紹介します。

Bean が@Statefulの場合、クエリを何度も送信することを避けたいため、何らかの方法で Bean のライフサイクルでデータを返そうとしていると思います。問題は、それを行う必要がないということです。Bean を@Statelessにして、多くのクエリでデータベースに負荷をかけるのを避けることができます。あなたがする必要があるのは@NamedQueryを作成することです。

したがって、エンティティPriceStep@NamedQueryで注釈を付け、そこに作成したクエリ文字列を入力します。このリンクでは、@NamedQueriesの使用方法に関する情報が見つかります: http://docs.oracle.com/cd/B31017_01/web.1013/b28221/ent30qry001.htm

次にお勧めするのは、クラスPriceManagementBean* @Stateless *という注釈を付けることです。各リクエストで新しい entityManager が作成されても心配しないでください。これは、ドメイン モデルと対話するため、データベースにまったく負荷をかけません。@PostConstruct は必要ありません。必要なときに @NamedQuery を呼び出すだけです。アプリサーバーはそれをキャッシュし、データベースと常に対話することなく、それを必要とする各ユーザーに返します.

ここにコードニペット:

@Entity
@NamedQuery(
    name="allPriceSteps",
    queryString="SELECT ps FROM PriceStep ps"
)
public class PriceStep implements Serializable {
...
}

今ビーン:

@Stateless
public class PriceManagementBean implements PriceManagement {

    @PersistenceContext
    private EntityManager em;

    public List<PriceStep> getAllPriceSteps() {
         Query query =  em.createNamedQuery("allPriceSteps");
         return query.getResultList();
     }
}

これが役に立つことを願っています。システム要件に関する詳細情報を提供していただければ、ベスト プラクティスに関するアドバイスを提供できます。

于 2012-05-26T15:03:48.830 に答える
-2

要件に基づいて、次のことを試してください

  • @Stateful を削除[一度に両方を使用することはできません]

  • @Startup は、APPLICATION INIT 中にシングルトン Bean を初期化します [アプリケーションが完全に初期化されていないことに注意してください]。これにより、EntityManager の読み込みに問題が発生する可能性があり、EntityManager ブリッジが完全に初期化されていないと思います。アプリケーションの完全な起動後に init の呼び出しを試みます [つまり] @Startup を削除します

于 2012-05-28T09:21:13.567 に答える