SQL Serverトランザクションでレコードレベルのロックを使用するにはどうすればよいですか?
-
27-09-2019 - |
質問
何年も前に、もともとデスクトップアプリとして作成されたアプリケーションがあります。編集画面を開くたびにトランザクションを開始し、[OK]をクリックするとコミットし、[キャンセル]をクリックするとロールバックします。これはデスクトップアプリでは問題なく機能しましたが、現在ADO.NETとSQL Serverに移行しようとしているため、長時間実行されるトランザクションに問題があります。
複数のユーザーがすべて同じテーブル(の異なるサブセット)を同時に編集しようとすると、問題が発生することがわかりました。古いデータベースでは、各ユーザーのトランザクションは、トランザクション中に変更したすべてのレコードに対するレコードレベルのロックを取得していました。さまざまなユーザーがさまざまなレコードを編集していたため、全員が独自のロックを取得し、すべてが機能します。ただし、SQL Serverでは、1人のユーザーがトランザクション内のレコードを編集するとすぐに、SQLServerはテーブル全体をロックしているように見えます。2人目のユーザーが同じテーブル内の別のレコードを編集しようとすると、最初のユーザーがコミットするかロールバックするまでSqlConnectionがブロックされるため、2番目のユーザーのアプリは単にロックアップします。
長時間実行されるトランザクションが悪いことを認識しています。最善の解決策は、これらの画面を変更して、トランザクションを長時間開いたままにしないようにすることです。しかし、それは侵襲的でリスクの高い変更を意味するので、このコードをそのまま稼働させる方法があるかどうかも調査したいと思います。そうすれば、自分の選択肢が何であるかがわかります。
SQL Serverで2人の異なるユーザーのトランザクションを取得して、テーブル全体ではなく個々のレコードをロックするにはどうすればよいですか?
これは、問題を説明する手っ取り早いコンソールアプリです。 ID(int)列とValue(nvarchar)列だけを持つ「Values」という1つのテーブルを持つ「test1」というデータベースを作成しました。アプリを実行すると、変更するIDを要求され、トランザクションが開始され、そのレコードが変更されてから、Enterキーを押すまでトランザクションが開いたままになります。できるようになりたい
- プログラムを起動し、ID1を更新するように指示します;
- トランザクションを取得してレコードを変更します。
- プログラムの2番目のコピーを開始し、ID2を更新するように指示します。
- 最初のアプリのトランザクションがまだ開いている間に更新(およびコミット)できるようにします。
現在、アプリの最初のコピーに戻ってアプリを閉じるか、Enterキーを押してコミットするまで、手順4でフリーズします。 command.ExecuteNonQueryの呼び出しは、最初の接続が閉じられるまでブロックされます。 ジェネラコディセタグプレ
動作に変更を加えずに、私がすでに試したことがいくつかあります。
- トランザクション分離レベルを「コミットされていない読み取り」に変更する
- UPDATEステートメントで「WITH(ROWLOCK)」を指定する
解決
確認するだけですが、ID列に主キーまたは一意のインデックスがありますか?
他のヒント
楽観的ロックと悲観的ロックを比較してください。
編集: 古典的なadoにリンクされた前の記事...ごめんなさい。
http://msdn.microsoft.com/en-us / library / cs6hb8k4(VS.71).aspx
おそらく、インデックスは行ロックを「オフ」に設定して作成されました。
その場合、クエリの「WITH(ROWLOCK)」は効果がありません。
ALTER INDEX を使用してそれらをオンに戻すことができます。: ジェネラコディセタグプレ