web-dev-qa-db-ja.com

SQL Serverスナップショット分離レベル:更新の競合を作成する方法?

トランザクションレベルのスナップショット(ReadCommmittedSnapshotIsolationではない)を使用して「更新の競合」を作成する方法の例はありますか?

エラーメッセージの例

更新の競合により、スナップショット分離トランザクションが中止されました。スナップショット分離を使用して、データベース「FoodDatabase」のテーブル「Food」に直接または間接的にアクセスして、別のトランザクションによって変更または削除された行を更新、削除、または挿入することはできません。トランザクションを再試行するか、更新/削除ステートメントの分離レベルを変更してください。

以下は機能していません:

create database FoodDatabase;
alter database FoodDatabase SET ALLOW_SNAPSHOT_ISOLATION ON;

create table dbo.food
(
    FoodId int primary key identity(1,1),
    FoodDesc varchar(255) null,
)

insert into dbo.food
values ('broccoli'), ('strawberry')

Transaction Session 1:
set transaction isolation level snapshot
begin transaction -- do not commit transaction yet
update Food
set FoodDesc = 'Grape' where FoodId = 1

Transaction Session 2:
set transaction isolation level snapshot
begin transaction -- do not commit transaction yet
update food
update Food
set FoodDesc = 'Lettuce' where FoodId = 1
3
user129291

SQL Serverバージョンを使用しています:

Microsoft SQL Server 2017(RTM-CU1)(KB4038634)-14.0.3006.16(X64)

この順序でスクリプトを実行すると、Update Conflictをシミュレートできます。

接続1

CREATE DATABASE FoodDatabase;
GO
ALTER DATABASE FoodDatabase SET ALLOW_SNAPSHOT_ISOLATION ON;
GO 

USE [FoodDatabase];
GO

CREATE TABLE dbo.food
(
    FoodId int PRIMARY KEY IDENTITY(1,1),
    FoodDesc varchar(255) null,
);
GO

INSERT INTO dbo.food
VALUES ('broccoli'), ('strawberry');
GO

--Transaction Session 1:
SET TRANSACTION ISOLATION LEVEL SNAPSHOT
BEGIN TRANSACTION -- do not commit transaction yet
UPDATE dbo.Food
SET FoodDesc = 'Grape' WHERE FoodId = 1;

出力:

(2行が影響を受けました)

(1行が影響を受けました)

接続2

--Transaction Session 2:
USE [FoodDatabase];
GO
SET TRANSACTION ISOLATION LEVEL SNAPSHOT
BEGIN TRANSACTION -- do not commit transaction yet
UPDATE dbo.Food
SET FoodDesc = 'Lettuce' WHERE FoodId = 1;

接続2からのセッションは接続1によってブロックされます。ロックの詳細を表示するには、Adam Machanicによって作成された sp_whoIsActive を使用します。

<lock_type>keylock</lock_type>
    <database_name>FoodDatabase</database_name>
    <hobt_id>72057594043105280</hobt_id>
    <schema_name>dbo</schema_name>
    <object_name>food</object_name>

Connection 1ウィンドウに戻り、COMMITステートメントを実行します。 Connection 2メッセージタブに次のエラーメッセージが表示されます。

メッセージ3960、レベル16、状態3、行6スナップショット分離トランザクションは、更新の競合のために中止されました。スナップショット分離を使用して、データベース 'FoodDatabase'のテーブル 'dbo.food'に直接または間接的にアクセスして、別のトランザクションによって変更または削除された行を更新、削除、または挿入することはできません。トランザクションを再試行するか、更新/削除ステートメントの分離レベルを変更してください。

役立つリソース:

利用可能なトランザクション分離レベルについて

2
SqlWorldWide