SQL Server 2016 - 创建不存在的记录时存储过程锁定

SQL Server 2016 - stored procedure lock when creating not existing records

我的数据库中有以下表格:

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

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

事件定义 (1) <- 事件 (n)
EventDefinition 对 EventSystem 和 Code 有唯一约束。

我正在开发一个存储过程,该过程应根据指定的代码和事件系统创建一个事件记录并将其映射到正确的 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 代码在程序并行执行时会产生死锁。

您的代码过于复杂。 Sql 服务器进行最多的检查并阻止自己。 只需 try/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