2016-08-24 57 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

相关问题