私のアプリケーションには、次のアクティビティが行われるコードがあります
1. ファイルを生成するデータ生成用のスクリプト A を実行します
。 2. ファイルを解析し、ファイルからデータを読み取ります
。
4. スクリプト Bを実行します。 5. B
によって生成された解析ファイル
6. データを 2 つの異なるテーブルに保存し、保存する前に、その日付の既存の行を古いものとしてマークします。
7.アクティビティ監査をテーブルに記録し、メールを送信する
これらの 7 つの手順は、10 ~ 12 の異なるエンティティに対して並行して実行されます。プラットフォームは JAVA、Spring、Ibatis で、READ COMMITTED として ISOLATION LEVEL を持つ新しいトランザクションで各スレッドのプロセス全体を実行しています。スレッドは、corepoolsize=maxPoolsize が 10 の ThreadPoolExecutor によって管理されます。テーブルのサイズは約 30K で、各テーブルの書き込みまたは更新されるデータの量は約 100 行です。使用されているデータベースは SQL サーバーです。
問題は、 @Transactional 表記がなくても期待どおりに機能することですが、各スレッドのトランザクションで 7 つのステップが実行されると、プロセスがスタックし、単純に処理が進まなくなります。一時停止状態のクエリを調査すると、3 ~ 4 つのクエリがステップ 3 を実行しようとしていて、「その日付の既存のエントリを古いものとして更新する」ことでスタックしていることが判明しました。これもロックのエスカレーションにつながり、5 ~ 10 分後にデータベース全体がロックされ、デッドロックのようなものにつながる他の操作が妨げられます。
実際のデッドロックは発生しないことに注意してください。操作は単に進行しません。
試した解決策: テーブルに非クラスター化インデックスを作成して、SQL サーバーが特定の行を識別してロックできるようにします。
問題の解決策または考えられる原因を提案してください。
編集
いくつかの調査と分析の後、解決策を見つけました。すべてのデータが生成された後、スレッドの最後にステップ 3、6、7 を移動しました。そのため、これらのステップは別のメソッドで実行され、@Transaction 表記はトランザクションでスレッド操作全体を実行するのではなく、メソッドにのみ適用されます。さらに、このメソッドは「同期」メソッドになりました。これにより、10 個のスレッドがアクティブであっても、任意の時点で 1 つのスレッドのみが DB に書き込みます。したがって、複数のスレッドが DB に書き込もうとする心配がなくなります。同時に。
私はこのアプローチをテストしましたが、以前に見られた問題は現在存在していませんが、@Transactionalの両方でメソッドに注釈を付けて同期させるかどうかを知りたかっただけです望ましくない影響を与えるため、問題ありません。さらに、同期された方法で DB に書き込むことをお勧めします。
以前の問題の実際の原因に興味がある人のために、正しいかもしれないし正しくないかもしれない考えられる理由を述べました。スレッドがスタックする原因として考えられるのは、Apache DBCP プールの最大サイズが 8 DB 接続であるのに対し、スレッド プール エグゼキューターの最大サイズが 10 スレッドであったことです。したがって、1 つの最初のスレッドがトランザクションに入り、5 分 (minEvicatableTime) を超えてアイドル状態のままになると、そのスレッドは強制排除され、その接続は別のスレッドに与えられました。テーブルが最初のスレッドによってロックされたため、接続を取得した他のスレッドはデータを書き込むことができませんでしたが、最初のスレッドは DB 接続がないため完了できませんでした。