私の開発環境では、MSSQL 2005 で直面している運用上の問題を再現しようとしています。この問題には 2 つの部分があります。
問題
1) デッドロックが発生し、MSSQL は 1 つの接続 (「接続 X」) を「被害者」として選択します。2) 「接続 X」を使用する後続の試みはすべて失敗します (接続プーリングを使用します)。MSSQL は「サーバーはトランザクションを再開できませんでした」と言う
2 つのうち、より深刻な場合は #2: 「接続 X」は「接続 X」を再利用しようとするすべての「ラウンド ロビン」試行が失敗するため、ミステリアスな「ランダム」エラーがユーザーに表示されます。サーバーを再起動する必要があります。
私が書く理由
ただし、この時点で、問題 1 を再現したいと思います。簡単にデッドロックを作成できます。
しかし、ここに私の問題があります: 本番環境では、MSSQL は 1 つの接続 (SPID) を「デッドロックの犠牲者」として選択しますが、私のテスト環境では、デッドロックがハングするだけです...そしてハングしてハングします。永遠に?よくわかりませんが、一晩ぶら下げたままにしておいて、朝になってもまだぶら下がっていました。
では、ここで質問です。デッドロックが発生したときに、SQL サーバーに「デッドロックの犠牲者を選択」させるにはどうすればよいでしょうか。
これまでの試み
jdbc url (「lockTimeout=5000」) を介して「lock_timeout」パラメーターを設定しようとしましたが、本番環境とは異なるメッセージが表示されました (テストでは、「ロック要求のタイムアウト期間を超えました。」本番環境では「トランザクション (プロセス) ID 59) は、別のプロセスとのロック リソースでデッドロックされ、デッドロックの犠牲者として選択されました。")
問題#2の詳細
この「トランザクションを再開できません」という問題を調査したところ、いくつかのことがわかりました。
- 不適切な例外処理がこの問題を引き起こす可能性があります。例: Java コードは Statement/PreparedStatement を閉じず、ドライバーの「接続」の実装は、不良/古い/古い「トランザクション ID」でスタックしています。
- jdbc ドライバーをアップグレードすると、問題が解決する場合があります。
ただし、今のところ、デッドロックを再作成し、SQL サーバーに「デッドロックの犠牲者を選択」させたいだけです。
前もって感謝します!
付録 A. 技術環境
発達:
- SQL サーバー 2005 SP3 (9.00.4035.00)
- ドライバー: sqljdbc.jar バージョン 1.0
- JBoss 3.2.6
- jdbc URL: jdbc:sqlserver://<>;
製造:
- SQL サーバー 2005 SP2 (9.00.3042.00)
- ドライバー: sqljdbc.jar バージョン 1.0
- JBoss 3.2.6
- jdbc URL: jdbc:sqlserver://<>;
付録 B. デッドロックを強制する手順
- 接続 A を取得する
- 接続 B を取得する
- 接続Aでsql1を実行します
- 接続 B で sql2 を実行します
- 接続 B で sql1 を実行します
- 接続Aでsql2を実行します
where sql1: update member set name = name + 'x' WHERE member_id = 71
sql2: update member set name = name + 'x' WHERE member_id = 72