Tomcatの2つの別々のインスタンスで実行されているタスクスレッドがあります。タスクスレッドは、特定のwhere条件で(selectを使用して)TASKSテーブルを同時に読み取り、いくつかの処理を実行します。
問題は、両方のスレッドが同じタスクを選択することがあるため、タスクが2回実行されることです。私の質問は、TASKSテーブルから同じデータセットを読み取らないように両方のスレッドを作成するにはどうすればよいですか?
Tomcatの2つの別々のインスタンスで実行されているタスクスレッドがあります。タスクスレッドは、特定のwhere条件で(selectを使用して)TASKSテーブルを同時に読み取り、いくつかの処理を実行します。
問題は、両方のスレッドが同じタスクを選択することがあるため、タスクが2回実行されることです。私の質問は、TASKSテーブルから同じデータセットを読み取らないように両方のスレッドを作成するにはどうすればよいですか?
コード(データベースにアクセスしている)のDAO機能が同期していないからです。同期させれば問題は解決すると思います。
TASKS table
あなたが言及しているのがデータベーステーブルである場合、私はトランザクション分離を使用します。
提案として、トランザクション内で、の属性を、設定されてTASK table
いない場合は一意の識別可能な値に設定します。トラクションをコミットします。すべてOKの場合、タスクはスレッドによって選択されています。
私はこのユースケースに出くわしたことがないので、私の提案をcatuionで扱ってください。
Quartzなどのエンタープライズジョブスケジューラでどのように機能するかについて、いくつかの情報を確認する必要があると思います。
あなたのユースケースには、仕事のためのより良いツールがあります-そしてそれはメッセージングです。作業が必要なアイテムを永続化してから、ワーカー間のアクセスを同期しようとしています。この作業を行う際に解決する必要のある問題がいくつかあります。一般に、テーブルの更新とテーブルからの選択を混在させないでください(ロックします)。そのため、そこに状態を保存しても機能しません。サーバーの再起動後も存続しないため、Javaコードでの同期も行われません。
ActiveMQなどのメッセージブローカーでJMSAPIを使用すると、メッセージをキューに公開します。このメッセージには、実行するタスクの詳細が含まれます。メッセージブローカーは、これをどこか(独自のメッセージストアまたはデータベースのいずれか)に保持します。次に、ワーカースレッドはメッセージブローカーのキューにサブスクライブし、各メッセージはそのうちの1つにのみ渡されます。これは非常に強力なモデルです。何百ものメッセージコンシューマーがすべてタスクを実行できるため、適切に拡張できます。これを必要なだけ回復力のあるものにすることもできるので、タスクはTomcatとブローカーの再起動の両方に耐えることができます。
データベースがこれを適切に管理できるかどうかは、並行性を管理するために厳密な2フェーズロック(S2PL)またはマルチバージョン並行性制御(MVCC)技術を使用しているかどうかに大きく依存します。MVCCでは、読み取りは書き込みをブロックしません。その逆も同様です。したがって、これを比較的単純なロジックで管理することは非常に可能です。S2PLでは、データベースをブロックするのに時間がかかりすぎて、これを管理するための優れたメカニズムにならないため、外部メカニズムを検討することをお勧めします。もちろん、外部メカニズムはデータベースに関係なく機能します。MVCCでは実際には必要ありません。
MVCCを使用するデータベースは、PostgreSQL、Oracle、MS SQL Server(特定の構成)、InnoDB(SERIALIZABLE分離レベルを除く)、およびおそらく他の多くのデータベースです。(これらは私が手に負えないことを知っているものです。)
使用しているデータベース製品についての質問では何の手がかりも得られませんでしたが、PostgreSQLの場合は、アドバイザリロックの使用を検討することをお勧めします。 http://www.postgresql.org/docs/current/interactive/explicit-locking.html#ADVISORY-LOCKS 他の製品の多くにも同様のメカニズムがあると思います。
行の最終変更日を保持する変数(列)が必要だと思います。スレッドは、同じ変更日制限で同じデータセットを読み取ることができます。
編集: 私は 「読まない」を見ませんでした
この場合、別のテーブルTaskExecutor(taskId、executorId)が必要であり、一部のスレッドがタスクを実行するときに、データをTaskExecutorに配置します。また、別のスレッドを開始すると、タスクがすでに実行されているかどうかがチェックされます(RanTaskから...を選択します。ここでtaskId = ...)。Нouは、トランザクションの分離レベルにも注意を払う必要があります。