2017-08-08 15 views
0

データベースへの接続プール内で同時に最大20の接続がアクティブになるデフォルトのstandalone.xml構成があります。正当な理由があると思います。 Oracleデータベースを実行します。Java-EEデータベース接続プールの実行が最大になっています

サードパーティのAPIトラフィックが存在するため、妥当な量のデータベーストラフィックがあります。私が開発しているエンタープライズアプリケーションのSOAPとHTTP呼び出し。エンティティがフェッチされ、(トランザクション全体が行われ、実際に)更新後にリリースされたときに

@PersistenceContext(unitName = "some-pu") 
private EntityManager em; 

public void someBusinessMethod() { 
    someEntity = em.findSomeEntity(); 
    soap.callEndPoint(someEntity.getSomeProperty()); // may take up to 1 minute 
    em.update(someEntity); 
    cdiEvent.fire(finishedBusinessEvent); 
} 

ただし、この場合には、データベース接続が取得されています

は、私たちはしばしば、以下のような何かを行います。トランザクションについては、すべてがコンテナ管理であり、追加の注釈はありません。私はあなたが必要以上にデータベース接続を「保持」してはならないことを知っています。これは私が解決しようとしているものです。私はプログラム的にコネクションを解放する方法も知らず、トランザクション全体をロールバックできるようにしたいので、これは良いアイデアだとは思っていません。

だから?この問題をどのように攻撃するのですか? ManagedExecutorServiceを使用して

オプション1、::

@Resource 
private ManagedExecutorService mes; 

public void someBusinessMethod() { 
    someEntity = em.findSomeEntity(); 

    this.mes.submit(() -> { 
     soap.callEndPoint(someEntity.getSomeProperty()); // may take up to 1 minute 
     em.update(someEntity); 
     cdiEvent.fire(finishedBusinessEvent); 
    }); 
} 

オプション2、@Asynchronousを使用して:

@Inject 
private AsyncBean asyncBean; 

public void someBusinessMethod() { 
    someEntity = em.findSomeEntity(); 
    this.asyncBean.process(someEntity); 
} 

public class AsyncBean { 

    @Asynchronous 
    public void process() { 
     soap.callEndPoint(someEntity.getSomeProperty()); // may take up to 1 minute 
     em.update(someEntity); 
     cdiEvent.fire(finishedBusinessEvent); 
    } 

} 

これは、実際には、例えば、データベース接続プールの問題を解決し、私が試した多くのオプションがありますsoap.callEndPointが発生するとすぐに接続が解除されます。しかし、それは本当に安定していませんでした(ここで問題を特定することはできません)。もちろん、a-sync処理を開始するとトランザクションは終了します。そのため、石鹸呼び出し中に何か問題が生じたときには、何もロールバックされませんでした。

ラッピングアップ... 私は一度キューのを経由してオフロードアプリケーションの別の部分に長い実行中のIOタスク(石鹸とHTTP呼び出し)を移動しようとしてだとキューのを経由して戻ってアプリケーションに結果を供給再び。この場合、すべてがトランザクションを介して行われ、接続は保持されません。しかし、これはオーバーヘッドが多いため、この問題を解決する方法について、あなたの意見やベストプラクティスをお聞きしたいと思います!

+0

正常に実行され、ピーク時に実行されている同時Webリクエストの数はいくつですか? –

+0

約50〜100、ピーク時は約200です。Wildflyは、プールから接続を取得すると失敗するまで約30秒待機するように設定されています。再試行はありません。 – Velth

+0

同じエンティティに対する同時変更を扱うための戦略は何ですか? –

答えて

0

コールの前に読み取り操作のみを実行する場合、キューの解決策は実行可能ですが、必要ではない場合は、DAOパターンを使用してトランザクションを2つのトランザクションに(キューと同様に)分割できます。

例:

@Stateless 
private DaoBean dao; 

@TransactionAttribute(TransactionAttributeType.NEVER) 
public void someBusinessMethod() { 
    Entity e = dao.getEntity(); // creates and discards TX 
    e = soap.callEndPoint(e.getSomeProperty()); 
    dao.update(e); // creates TX 2 and commits 
} 

このソリューションは、いくつかの注意事項があります。それはDAO(NOT_SUPPORTEDで懸濁1つのTX)の目的を否定することになるため、トランザクションが既にアクティブである間

  • 上記ビジネス方法を呼び出すことはできません。
  • soap呼び出し中にエンティティで発生した可能性のある変更(@ Version ...)を処理または無視する必要があります。
  • エンティティはビジネスメソッドでデタッチされるため、SOAPコールで必要なものすべてを読み込む必要があります。

ビジネスコールの前に行われたことに応じて、これが機能するかどうかはわかりません。それでも複雑ではあるが、キューよりも簡単です。

+0

私はあなたの目的のソリューションが実際に動作するかどうか疑問に思うので、すぐにトランザクションを入力します:-(dao.getEntity() 'の' @Transactional(Transactional.TxType.REQUIRES_NEW)データベースからフェッチを終了したら破棄してください(汚れた読み込み)?そのため、SOAPコールを呼び出すときに接続が保持されませんが、可能性のある競合のために@Versionを実装する必要があります。 – Velth

0

オプション2を使用すると、適切なトラックに向かうことができました。トランザクション管理を非常に短く保つようにするには、もう少し分解が必要です。

あなたが潜在的に長い実行中のWebサービスを持っているので、あなたは間違いなく、二つの別々のトランザクションでデータベースの更新を実行する必要があるとしている呼び出し:

  1. 短い検索操作
  2. 長いWebサービスの呼び出し
  3. 短い更新操作

これは次のように第三のEJBを導入することによって達成することができる。

エントリポイント

@Stateless 
public class MyService { 

    @Inject 
    private AsyncService asyncService; 

    @PersistenceContext 
    private EntityManager em; 

    /* 
    * Short lived method call returns promptly 
    * (unless you need a fancy multi join query) 
    * It will execute in a short REQUIRED transaction by default 
    */ 
    public void someBusinessMethod(long entityId) { 
     SomeEntity someEntity = em.find(SomeEntity.class, entityId); 
     asyncService.process(someEntity); 
    } 

} 

プロセスWebサービス呼び出し

@Stateless 
public class AsyncService { 

    @Inject 
    private BusinessCompletionService businessCompletionService; 

    @Inject 
    private SomeSoapService soap; 

    /* 
    * Long lived method call with no transaction. 
    * 
    * Asynchronous methods are effectively run as REQUIRES_NEW 
    * unless it is disabled. 
    * This should avoid transaction timeout problems. 
    */ 
    @Asynchronous 
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) 
    public void process(SomeEntity someEntity) { 
     soap.callEndPoint(someEntity.getSomeProperty()); // may take up to 1 minute 
     businessCompletionService.handleBusinessProcessCompletion(someEntity); 
    } 
} 

完了まで

@Stateless 
public class BusinessCompletionService { 

    @PersistenceContext 
    private EntityManager em; 

    @Inject 
    @Any 
    private Event<BusinessFinished> businessFinishedEvent; 

    /* 
    * Short lived method call returns promptly. 
    * It defaults to REQUIRED, but will in effect get a new transaction 
    * for this scenario. 
    */ 
    public void handleBusinessProcessCompletion(SomeEntity someEntity) { 
     someEntity.setSomething(SOMETHING); 
     someEntity = em.merge(someEntity); 
     // you may have to deal with optimistic locking exceptions... 
     businessFinishedEvent.fire(new BusinessFinished(someEntity)); 
    } 

} 

私はあなたがまだあなたのピーク負荷と効果的に対処するためにいくつかの接続プールのチューニングが必要な場合がありますことを疑います。モニタリングはそれをクリアするべきです。

関連する問題