2016-08-24 51 views
0

當存儲過程鎖我在我的數據庫下表:的SQL Server 2016 - 創造不存在的記錄

------------------------------------------ 
| EventDefinitions      | 
------------------------------------------ 
| EventDefinitionId: uniqueidentifier | 
| Code:     varchar(63)  | 
| EventSystem:   int    | 
------------------------------------------ 

------------------------------------------ 
| Event         | 
------------------------------------------ 
| EventId:    uniqueidentifier | 
| EventDateTime:  datetime2  | 
| EventDefinitionId: uniqueidentifier | 
------------------------------------------ 

EventDefinitions(1)< - 事件(N)
EventDefinition具有唯一性約束事件系統和代碼。

我正在創建一個存儲過程,該存儲過程應根據指定的代碼和事件系統創建事件記錄並將其映射到正確的EventDefinition記錄。
如果不存在匹配的EventDefinition,則該過程應創建一個新的EventDefinition。
該過程將由多個應用程序同時執行。

我的目標:

  • 的程序必須是並行執行。
    儘可能少地鎖定,以便可以同時寫入多個事件記錄。
  • 當EventDefinition不存在時,它應該只由一個進程創建。
    該過程應該創建某種鎖,以確保只有一次創建帶有指定代碼和事件系統的EventDefinition記錄(否則數據庫將拋出唯一的約束違例異常)。 其他進程應將事件記錄映射到新創建的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代碼產生死鎖。

回答

1

您的代碼過於複雜。 Sql服務器執行最多的檢查並自行阻止。 只需嘗試/ catch插入,如果由於UNIQUE約束違反而失敗,請重新讀取EventDefinitions。種類

CREATE PROCEDURE dbo.procWriteEvent @eventCode varchar(63), @eventSystem int 
AS 
    DECLARE @eventDefinitionId uniqueidentifier 
    DECLARE @insertedEventDefinition table(EventDefinitionId uniqueidentifier) 
    DECLARE @currentLevel varchar(255) 
    -- 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 TRY 
     INSERT INTO EventDefinitions (Code, EventSystem, Severity) 
     OUTPUT Inserted.EventDefinitionId INTO @insertedEventDefinition 
     VALUES (@eventCode, @eventSystem, 0); 
     SET @eventDefinitionId = (SELECT TOP 1 EventDefinitionId FROM @insertedEventDefinition) 
    END TRY 
    BEGIN CATCH 
     SET @eventDefinitionId = (SELECT TOP 1 EventDefinitionId FROM EventDefinitions WHERE EventSystem = @eventSystem AND Code = @eventCode) 
    END CATCH 
    -- proceed with @eventDefinitionId value 
+0

非常感謝您的幫助。我不是爲什麼我試圖用這種複雜的方式解決這樣一個簡單的問題^^ – musium

相關問題