serテーブルがある場合:
_id | name | age
1 | Mateus | 27
_
最初のトランザクションは更新を実行し、コミットまたはロールバックせずにトランザクションを開いたままにします。
_update User set name = 'John' where id = 1;
_
一方、2番目のトランザクションは選択を実行します。
_select * from User where id = 1;
_
次のように2番目のトランザクションがテーブルヒントwith(nolock)
を使用しない限り、このコマンドは最初のトランザクションがコミットまたはロールバックによってロックを解放するまで待機します。select * from User with(nolock) where id = 1;
これにより、トランザクションをロックせずにレコードが返されますが、元のJohn
ではなく、コミットされていない値Mateus
が返されます。
私が知っていることから、現在のトランザクションをロックせずにロックされたレコードを返す方法は2つしかありません。レコードを返すwith(nolock)
を使用できますが、コミットされていない値を使用し、with(readpast)
それは単にレコードを返しません。
テーブルをロックせずに「古い」値を返すことなく、レコードを返す方法はありますか?
探しているのは、スナップショット分離や読み取りコミットスナップショット分離などの楽観的な分離レベルです。
USE Crap;
CREATE TABLE dbo.users (id INT, username NVARCHAR(40));
INSERT dbo.users ( id, username )
VALUES ( 1, N'Jimbo' )
/*To turn on Snapshot*/
ALTER DATABASE Crap SET ALLOW_SNAPSHOT_ISOLATION ON;
/*To turn on RCSI*/
ALTER DATABASE Crap SET READ_COMMITTED_SNAPSHOT ON;
UPDATE dbo.users
SET username = 'Dimbo'
WHERE id = 1;
/*Snapshot needs this, RCSI doesn't*/
SET TRANSACTION ISOLATION LEVEL SNAPSHOT
SELECT *
FROM dbo.users AS u
WHERE u.id = 1;
スナップショット分離とRCSIの重要な違いの1つは、トランザクション内です。
スナップショット分離では、BEGIN TRANはトランザクション内のすべてのクエリがバージョンストアから読み取るポイントをマークします。
RCSIでは、BEGIN TRANの後の各ステートメントは、ステートメントが実行された時点でバージョンストアを読み取ります。
もう1つの違いは、スナップショット分離が変更クエリに適用できることですが、RCSIは適用できません。より正確には、SIは書き込みの競合を検出し、競合するトランザクションの1つを自動的にロールバックします。 RCSIでの更新 更新するデータを見つけるときに行バージョンを使用しませんが、これはターゲットテーブルにのみ適用されます。ターゲットテーブルへの追加の参照を含む、同じ削除または更新ステートメント内の他のテーブルは、引き続き行バージョンを使用します。