2016-08-24 3 views
0

를 만들 때 프로 시저 잠금 저장 I했습니다 내 데이터베이스에서 다음과 같은 테이블 :SQL 서버 2016 - 존재하지 않는 기록

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

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

EventDefinitions (1) < - 이벤트 (n)이
EventDefinition이 고유 제한 조건에있다 EventSystem 및 코드.

나는 이벤트 레코드를 생성하고 지정된 코드 및 EventSystem을 기반으로 정확한 EventDefinition 레코드에 매핑해야하는 저장 프로 시저에 대해 작업하고 있습니다.
일치하는 EventDefinition이 없으면 절차에서 새 EventDefinition을 만들어야합니다.
절차는 여러 응용 프로그램에서 동시에 실행됩니다.

내 목표는 :

  • 절차는 병렬로 실행해야합니다.
    잠금을 가능한 한 적게 사용하면 여러 이벤트 레코드를 동시에 쓸 수 있습니다.
  • EventDefinition이없는 경우 하나의 프로세스 만 만들어야합니다.
    프로 시저에서는 지정된 Code 및 EventSystem이있는 EventDefinition 레코드가 한 번만 생성되도록 잠금을 설정해야합니다. 그렇지 않으면 DB에서 고유 한 제한 위반 예외가 발생합니다. 다른 프로세스는 이벤트 레코드를 새로 생성 된 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 Server는 대부분의 검사와 차단을 수행합니다. 삽입/삽입을 시도하면 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