12

いくつかのオブジェクトに対して何らかの操作を実行できるビジネスロジックメソッドがあるとします。たぶん、リストから選択された人ごとに1回、宝くじ番号選択Webサービスに電話をかけたいと思うかもしれません。Javaでは、コードは次のようになります。

Set<Person> selectedPeople = ... // fetch list of people
for ( Person person : selectedPeople ) {
    String lotteryNumber = callLotteryNumberWebService( person );
    // ...
}

宝くじ番号のWebサービスには、その人が宝くじ番号を要求したことを記録する(おそらくアカウントに請求する)などの副作用がある可能性があるため、ある人のWebサービス呼び出しが失敗した場合でも、他の人のWebサービス呼び出しは成功した可能性があることに注意してください。この情報(宝くじ番号)は、より高いレベル(ビュー)にフィードバックする必要があります。

これが単一の操作が行われた場合、ビジネスロジックメソッドは単一の値(たとえば、宝くじ番号)を返すか、失敗の詳細を含む例外をスローする可能性があります。ただし、一括操作の場合、いくつかの操作が成功し、いくつかが失敗する可能性があります。

これは多くのアプリケーションで発生するタイプの問題のようであり、それを処理するためのクリーンな方法があるはずです。では、このタイプの情報をビジネスロジックレイヤーからアプリケーションの別のレイヤー(ビューなど)にフィードバックするための最良の方法は何ですか?できれば、さまざまなタイプのデータや操作に再利用できる一般的な方法でしょうか?

4

8 に答える 8

10

この質問は、例外処理、トランザクション、およびアイデアワークフローの「補償」の適切な使用法の重要な違いを浮き彫りにします。

これは多くのアプリケーションで発生するタイプの問題のようであり、それを処理するためのクリーンな方法があるはずです。

これは一般的な問題です。まず、現在試みているトランザクションアプローチの背景を説明します。

データトランザクションは、もともと複式簿記をモデルにしていました。単一の貸方と対応する借方を一緒に記録するか、まったく記録しない必要がありました。トランザクションがこれより大きくなると、正しく実装するのがますます問題になり、障害に対処するのが難しくなります。システムの境界を越えて単一のトランザクションのアイデアを実行し始めると、おそらくそれを間違ってアプローチしていることになります。それは可能ですが、複雑で、必然的に待ち時間の長いトランザクションコーディネーターが必要です。ある規模では、取引は間違った考え方であり、補償ははるかに理にかなっています。

ここに戻って、ビジネスが実際に何をしているのかを見てみましょう。単一の大規模なトランザクションは、ビジネスマンがそれを見る方法ではない可能性があります。通常、彼らはステップが完了したことを確認し、その後の結果に応じて、補償するためのさまざまなアクションが必要になる場合があります。ここで、ワークフローと報酬のアイデアが登場します。 これらの概念の概要を1つ紹介します。

たとえば、Amazonに本を注文した場合、ショッピングカートに入っている間はレコードが「ロック」されないか、注文が確認されたときに本がまだ在庫があるかどうかを判断するために厳密なトランザクションを使用することさえありません。彼らはとにかくそれをあなたに売り、彼らができるときにそれを出荷します。彼らが数週間以内に在庫を得ることができなかった場合、彼らはおそらくあなたに彼らがあなたのニーズを満たそうとしていることを知らせる電子メールを送ります、そしてあなたは彼らがそれを在庫に入れるのを待つことができます、またはあなたご注文をキャンセルすることができます。これは補償と呼ばれ、多くの実際のビジネスプロセスで必要です。

最後に、これについて例外的なことは何もありません。これが発生する可能性があることを期待し、通常の制御フローを使用します。ここでは、言語の例外処理機能を使用しないでください(例外をスローするタイミングに関する適切なルール)。また、サービス実装内で発生する例外を確認または処理するために、ツール固有の(WCF?)メカニズムに依存するべきではありません。障害の伝達は、データコントラクト(障害コントラクト)の通常の部分である必要があります。

残念ながら、「クリーンな処理方法」では、魔法のように処理するフラグを設定することはできません。問題を分解し、結果として生じるすべての部分を処理し続ける必要があります。うまくいけば、これらの概念が、この問題に対処するときに他の人が行ったこととあなたを結びつけるでしょう。

概要:

  • あなたの問題はトランザクションの概念を超えてしまいました->ワークフローの報酬を調べてください。

幸運を -

于 2009-09-01T18:56:14.490 に答える
1

あなたがこれらの用語で考えているなら、あなたは本当に例外を使いすぎていると思います!

例外をスローするのではなく、失敗を意味する値を返すことはまったく問題ありません。多くの場合、それはより良いです。例外は、現在の抽象化レベルで回復できない場合に最適に使用されますが、制御フローの主な手段として使用しないでください。例外を使用すると、プログラムが非常に読みにくくなります。

Webサービスは例外を返さず、戻りコードとメッセージを返します。返された情報を提示するいくつかの有用な表現を保存し、ビューまたはそれを見ようとしているもののリストを返します。

于 2009-08-31T17:16:08.323 に答える
1

エラー、エラーコード、説明の影響を受ける、オブ​​ジェクトを識別するカスタムメイドのエラーオブジェクトのコレクションを返したいと思います。このようにして、エラーを修正したり、ユーザーにさらに表示したりすることができます。

于 2009-08-27T10:06:22.113 に答える
1

私が理解している場合、一部のリクエストは成功し、一部は失敗する可能性がある状況があります。エラーをどこに戻すかはわかりませんが、次のいずれか(またはバリアント、あるいはその組み合わせ)を使用できます。

  • エラーと影響を受けるドメインオブジェクトのリスト。ベースドメインオブジェクトまたは永続化可能なIDを持つものは、再利用に役立つ場合があります。たとえば、ドメインオブジェクトを参照するエラーのコレクション。
  • ある種のエラーオブジェクト/メッセージをPersonオブジェクトに注入することができます(AOP、DI)。例:if(person。errors){...}
  • Personコレクションをヘッダー、本文、エラー情報を含むメッセージにラップすることができます
  • すべてのドメインオブジェクトには、インターフェイスを介してアクセスできるエラーコレクションが含まれている可能性があります。またはPersonはIHasErrorsインターフェースをサポートします。これを汎用化し、警告や検証などのあらゆる方法をサポートする基本のErrorオブジェクトを使用できます。

(階層化ではなく)本物の多層システムを使用している場合は、ある種の一般的なエラー/警告/検証メカニズムに簡単に対応できるメッセージベースのアーキテクチャを使用している可能性があります。SOA/Ajaxシステムはこれに役立ちます。

特定の質問がある場合は、もう少し深く掘り下げてください。

于 2009-09-07T06:00:42.220 に答える
1

理想的には、Webサービスへの呼び出しは次のようになります。

List<Person> selectedPeople = ... //fetch list of people
callLotteryNumberWebService(selectedPeople.ToArray );

一人一人にWebサービスを呼び出すにはコストがかかります。サーバー側では、リストを繰り返し処理して操作を実行する必要があります。サーバー側のコードは、次の2つの例外をスローする可能性があります。BulkOperationFailedException-dbのダウンまたは構成ファイルの欠落が原因で致命的なエラーが発生した場合。それ以上の処理はできません。BulkOperationException-これには、個人に関連する一連の例外が含まれます。各オブジェクトを一意に参照するために、いくつかのIDを永続化できます。コードは次のようになります。

List<Person> selectedPeople = ... // fetch list of people 

try{
    callLotteryNumberWebService(selectedPeople.ToArray);
}catch  (BulkOperationFailedException e) {
    SOP("Some config file missing/db down.No person records processed")
}catch(BulkOperationException e)  {
    UserDefinedExceptions us =  e.getExceptions()
    foreach(exception ein us)   {
        // read unique id to find which person object failed
    }
}

construct msg based on which personobject succeeded and which failed

例外がスローされない場合、操作は成功したと見なされます。UserDefined例外を使用する代わりに、失敗のカスタムエラーコードを設定できます。サーバー側でBulkOperationExceptionを構築するのは難しいです。次に、サーバー側からスローされたエラーをBulkOperationFailedExceptionとBulkOperationExceptionに分類する必要があります。これは私が私のプロジェクトの1つで扱った方法でした

于 2009-09-07T08:43:30.487 に答える
0

私はおそらくMap<Person,Future<String>>私のgetLotteryNumbers<Collection<Person>>サービスからタイプの結果マップを返すでしょう。

次に、マップを繰り返し処理し、を使用しFuture.get()て宝くじ番号またはスローされた例外を取得します。

一部のサービスでは、すべての呼び出しを単一アイテムの呼び出しとして実装し、サービスにそれらをバッチ処理してグループとして処理するロジックを含めるのが好きです。バッチ処理は、LinkedBlockingQueueとポーリングスレッドを使用して実装されます。

このシナリオでは、Future<Thing>を使用してバッチ結果が利用可能になるのを待つaを返しますCountdownLatch

実際のJava同時実行性を見て、これらのコンポーネントがすべてどのように連携できるかを確認してくださいhttp://jcip.net/

于 2009-08-31T10:34:15.020 に答える
0

この種のタスクのDTOを調べます。DTOには、永続化が成功したかどうかに関する情報や、他の種類の「メタデータ」も含めることができます。

于 2009-08-31T13:43:48.897 に答える
0

別の方法、特に高スループットシステムの場合、処理エンティティがオブジェクトに対して操作を実行し、その結果に基づいてオブジェクトを別のキューに入れて他のエンティティによる追加の処理を行い、次に進むキューに基づく設計を使用することです。 。これにより、在庫切れの製品の注文処理など、必要となる追加の処理によって発生するボトルネックが軽減されます。

于 2009-09-02T09:27:28.423 に答える