9

現在、サーブレットに注入されるステートフルBeanがあります。問題はCaused by: javax.ejb.ConcurrentAccessException: SessionBean is executing another request. [session-key: 7d90c02200a81f-752fe1cd-1]、ステートフルBeanでメソッドを実行するときにが発生することがあることです。

public class NewServlet extends HttpServlet {  
    @EJB  
    private ReportLocal reportBean;

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
           String[] parameters  = fetchParameters(request);
           out.write(reportBean.constructReport(parameters));
        } finally { 
            out.close();
        }
    } 
}

上記のコードでconstructReportは、レポートで指定されたデータベースへの新しい接続を開く必要があるかどうかを確認します。その後、指定されたパラメータから作成されたクエリからHTMLのレポートが作成されます。

ステートレスBeanではなくステートフルBeanを使用することを選択した理由は、不明なデータベースへのデータベース接続を開いてクエリを実行する必要があるためです。ステートレスBeanでは、注入されたBeanのインスタンスごとにデータベース接続を繰り返し開いたり閉じたりするのは非常に非効率的です。

4

5 に答える 5

14

ConcurrentAccessExceptionに関するいくつかの詳細:EJB仕様に従って、SLSBへのアクセスはアプリによって同期されます。サーバ。ただし、これはSFSBには当てはまりません。SFSBが同時にアクセスされないようにする責任は、アプリケーション開発者の肩にかかっています。

なんで?SLSBの同期は、インスタンスレベルでのみ必要です。つまり、SLSBの特定のインスタンスはそれぞれ同期されますが、プール内またはクラスター内の異なるノードに複数のインスタンスがある場合があり、異なるインスタンスでの同時リクエストは問題になりません。残念ながら、これは、インスタンスのパッシベーション/アクティブ化とクラスター全体でのレプリケーションのため、SFSBではそれほど簡単ではありません。これが、仕様がこれを強制しない理由です。このトピックに興味がある場合は、このディスカッションをご覧ください。

これは、サーブレットからSFSBを使用するのが複雑であることを意味します。同じセッションから複数のウィンドウを使用しているユーザー、またはレンダリングが完了する前にページをリロードしているユーザーは、同時アクセスにつながる可能性があります。サーブレットで行われるEJBへの各アクセスは、理論的にはBean自体で同期する必要があります。私がしたことは、特定のEJBインスタンス上のすべての呼び出しを同期するInvocationHandlerを作成することでした。

public class SynchronizationHandler implements InvocationHandler {

 private Object target;  // the EJB

 public SynchronizationHandler( Object bean )
 {
        target = bean;
 }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  {
    synchronized( target )
    {
       // invoke method to the target EJB
    }
  }

}

次に、EJBへのリモート参照を取得した直後に、EJBをでラップしますSynchronizationHandler。このようにして、この特定のインスタンスがアプリから同時にアクセスされないようにします(1つのJVMでのみ実行されている場合)。Beanのすべてのメソッドを同期する通常のラッパークラスを作成することもできます。

それでも私の結論は、可能な限りSLSBを使用することです。

編集

この回答は、EJB 3.0の仕様(セクション4.3.13)を反映しています。

クライアントは、ステートフルセッションオブジェクトへの同時呼び出しを行うことはできません。同じまたは異なるクライアントからの別のクライアント呼び出し呼び出しがステートフルセッションBeanクラスの同じインスタンスに到達したときに、クライアント呼び出しビジネスメソッドがインスタンスで進行中の場合、2番目のクライアントがBeanのビジネスのクライアントである場合インターフェイスの場合、同時呼び出しにより、2番目のクライアントがjavax.ejb.ConcurrentAccessExceptionを受信する可能性があります

このような制限は、EJB 3.1(セクション4.3.13)で削除されました。

デフォルトでは、クライアントはステートフルセッションオブジェクトへの同時呼び出しを行うことができ、コンテナはそのような同時要求をシリアル化する必要があります。

[...]

Bean開発者は、オプションで、ステートフルセッションBeanへの同時クライアント要求を禁止するように指定できます。これは、値が0の@AccessTimeoutアノテーションまたはaccess-timeoutデプロイメント記述子要素を使用して行われます。この場合、同じまたは異なる別のクライアントが呼び出した呼び出しがインスタンスでクライアントによって呼び出されたビジネスメソッドが進行中の場合clientは、ステートフルセッションBeanの同じインスタンスに到達します。2番目のクライアントがBeanのビジネスインターフェイスまたは非インターフェイスビューのクライアントである場合、同時呼び出しにより、2番目のクライアントがjavax.ejb.ConcurrentAccessExceptionを受信する必要があります。

于 2009-12-20T10:29:45.717 に答える
9

これは、ステートフルセッションBean(SFSB)の使用目的ではありません。これらは会話状態を保持するように設計されており、セッションに状態を直接保存する代わりのヘビー級のように、ユーザーのhttpセッションにバインドしてその状態を保持する必要があります。

データベース接続のようなものを保持したい場合は、それを実行するためのより良い方法があります。

最良のオプションは、接続プールを使用することです。常に接続プールを使用する必要があります。アプリケーションサーバー内で実行している場合(EJBを使用している場合は、そのようになります)、アプリケーションサーバーのデータソース構成を使用して接続プールを簡単に作成し、ステートレスセッションBean(SLSB)内のそれ。

于 2009-12-20T09:32:50.960 に答える
1

コードとスタックトレースを提供するまでは、接続プールの使用を検討することをお勧めします。「不明なデータベース」とは、パラメーターがエンドユーザーによって提供されるデータベースを意味し、したがって事前構成された接続プールが不可能な場合でも、毎回新しい接続を開くのではなく、接続プールの概念を使用できます。

また、このスレッドをチェックしてください。

于 2009-12-20T08:54:11.240 に答える
0

サーブレットまたはejbアクセスを同期しないでください。これにより、リクエストキューが発生し、同時にN人のユーザーがいる場合、最後のユーザーは長時間待機し、タイムアウト応答を受け取ることがよくあります。Syncronizeメソッドはこの理由で意図されていません!!!

于 2011-07-14T07:19:29.980 に答える
0

セッションBeanは、クライアントセッションに対応する状態を処理するためのものであり、通常はクライアントごとにセッションオブジェクトに格納されるとskaffmanが述べたように、同時に使用することはできません。

データベースプールを使用してリソースへの同時リクエストを処理するようにリファクタリングするのが最善の方法です。

それまでの間、必要なのがこの些細な使用だけである場合は、次のようにconstructReportの呼び出しを同期できます。

synchronised (reportBean) {
       out.write(reportBean.constructReport(parameters));
}

ConstructReportがクライアントの数に比べてかなりの時間がかかる場合、これは解決策ではないことに注意してください。

于 2009-12-20T09:48:53.313 に答える