を作成するときに私は、データベース内の次の表ました:SQL Serverの2016 - ストアドプロシージャのロック既存のない記録に
------------------------------------------
| EventDefinitions |
------------------------------------------
| EventDefinitionId: uniqueidentifier |
| Code: varchar(63) |
| EventSystem: int |
------------------------------------------
------------------------------------------
| Event |
------------------------------------------
| EventId: uniqueidentifier |
| EventDateTime: datetime2 |
| EventDefinitionId: uniqueidentifier |
------------------------------------------
をEventDefinitions(1)< - イベント(N)
EventDefinitionが上で一意制約を持ちますイベントシステムとコード。
私はイベントレコードを作成し、指定されたコードとEventSystemに基づいて正しいEventDefinitionレコードにマップするストアドプロシージャに取り組んでいます。
一致するEventDefinitionが存在しない場合、プロシージャは新しいEventDefinitionを作成する必要があります。
この手順は、複数のアプリケーションによって同時に実行されます。
私の目標:
- 手順は、並列実行可能でなければなりません。
ロックをできるだけ少なくすることで、複数のイベントレコードを同時に書き込むことができます。 - EventDefinitionが存在しない場合は、1つのプロセスで作成する必要があります。
プロシージャは、指定されたCodeおよびEventSystemを持つEventDefinitionレコードが1回だけ作成されるようにロックを作成する必要があります(そうしないと、DBは一意の制約違反例外をスローします)。 他のプロセスは、Eventレコードを新しく作成したEventDefinitionレコードにマップする必要があります。ここで
私がこれまで試したものです:
CREATE PROCEDURE dbo.procWriteEvent @eventCode varchar(63), @eventSystem int
AS
DECLARE @eventDefinitionId uniqueidentifier
DECLARE @insertedEventDefinition table(EventDefinitionId uniqueidentifier)
DECLARE @currentLevel varchar(255)
BEGIN TRANSACTION
-- Try read event definition
SET @eventDefinitionId = (SELECT TOP 1 EventDefinitionId FROM EventDefinitions WHERE EventSystem = @eventSystem AND Code = @eventCode)
-- Create event definition if not exists
IF @eventDefinitionId IS NULL
BEGIN
BEGIN TRANSACTION
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
-- Check if event definition was created by an other process
SET @eventDefinitionId = (SELECT TOP 1 EventDefinitionId FROM EventDefinitions WHERE EventSystem = @eventSystem AND Code = @eventCode)
-- Create event definition
IF @eventDefinitionId IS NULL
BEGIN
INSERT INTO EventDefinitions (Code, EventSystem, Severity)
OUTPUT Inserted.EventDefinitionId INTO @insertedEventDefinition
VALUES (@eventCode, @eventSystem, 0)
SET @eventDefinitionId = (SELECT TOP 1 EventDefinitionId FROM @insertedEventDefinition)
END
COMMIT TRANSACTION
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
END
INSERT INTO Events (EventDefinitionId, EventDateTime)
VALUES (@eventDefinitionId, GETDATE())
COMMIT TRANSACTION
問題手続きを並列に実行されたとき、私の現在のSQLコードは、デッドロックが発生します。
ありがとうございました。私はなぜそんなに簡単な問題を複雑な方法で解決しようとしなかったのですか^^ – musium