2011-03-31 6 views
2

특정 테이블에 삽입/업데이트/삭제할 때마다 AuditTable에 새 레코드를 삽입하는 삽입/업데이트/삭제 트리거가 있습니다. AuditTable의 삽입이 실패하면 첫 번째 레코드를 삽입하고 오류가 더 많은 테이블 "AuditErrors"에 기록되기를 바랍니다.MSSQL 트리거가 실패 할 때 롤백 방지

이것은 내가 지금까지 가지고 많은 시도를했지만 AuditTable에 트리거 삽입이 실패하면이 작업을 수행 할 수 없습니다 (AuditTable 삽입의 열 이름을 잘못 입력하여 테스트 함) . 주의 : @sql은 AuditTable에 삽입됩니다.

DECLARE @TranCounter INT 
SET @TranCounter = @@TRANCOUNT 
IF @TranCounter > 0 
    SAVE TRANSACTION AuditInsert; 
ELSE 
    BEGIN TRANSACTION; 
BEGIN TRY 
    EXEC (@sql) 
    IF @TranCounter = 0 
    COMMIT TRANSACTION; 
END TRY 
BEGIN CATCH 
    -- roll back 
    IF @TranCounter = 0 
    ROLLBACK TRANSACTION; 
    ELSE 
    IF XACT_STATE() <> -1 
     ROLLBACK TRANSACTION AuditInsert; 
    -- insert error into database  
    IF @TranCounter > 0 
    SAVE TRANSACTION AuditInsert; 
    ELSE 
    BEGIN TRANSACTION; 
    BEGIN TRY 
    INSERT INTO [dbo].[AuditErrors] ([AuditErrorCode], [AuditErrorMsg]) VALUES (ERROR_NUMBER(), ERROR_MESSAGE()) 
    IF @TranCounter = 0 
     COMMIT TRANSACTION; 
    END TRY 
    BEGIN CATCH 
    -- roll back 
    IF @TranCounter = 0 
     ROLLBACK TRANSACTION; 
    ELSE 
     IF XACT_STATE() <> -1 
     ROLLBACK TRANSACTION AuditInsert; 
    END CATCH 
END CATCH 

답변

2

이것은 원래 트랜잭션과 트리거 작업을 구분하는 유일한 방법입니다. 이 예제에서는 감사 삽입이 실패하더라도 원본 삽입이 완료됩니다. 2008R2에서 테스트되었습니다.

꽤 아니지만 트랜잭션을 롤백하지 않습니다!

그것은 신뢰할 수있는 인증과 함께 잘 일 :

create table TestTable(
    ID int identity(1,1) not null 
    ,Info varchar(50) not null 
    ) 
GO 
create table AuditTable(
    AuditID int identity(1,1) not null 
    ,TestTableID int not null 
    ,Info varchar(10) -- The failure is the mismatch in length 
) 
GO 

create procedure insertAudit @id int, @Info varchar(50) 
as 
set nocount on; 
begin try 
    insert into AuditTable(TestTableID,Info) 
    values(@id,@Info); 
end try 
begin catch 
    select 0 
end catch; 
GO 

create trigger trg_TestTable on TestTable 
AFTER INSERT 
as 
begin 
set nocount on; 

declare @id int, 
     @info varchar(50), 
     @cmd varchar(500), 
     @rc int; 
select @id=ID,@info=Info from inserted; 

select @cmd = 'osql -S '[email protected]@SERVERNAME+' -E -d '+DB_NAME()+' -Q "exec insertAudit @id='+cast(@id as varchar(20))+',@Info='''[email protected]+'''"'; 

    begin try 
     exec @rc=sys.xp_cmdshell @cmd 
     select @rc; 
    end try 
    begin catch 
     select 0; 
    end catch; 
end 
GO 

는 감사 테이블을 삭제하고 여전히 원래 트랜잭션을 완료합니다.

건배!

+0

환호 동료, 나는 시도하지 않은 : 데이터가 감사 테이블에 삽입 된 트랜잭션이 롤백됩니다 경우

당신이해야 할 모든 @Sql의 코드의 실행을 반복하는 것입니다 이 아직 그러나 나는 어떤 단계에서 당신에게 알려줄 것입니다! – Martin

0

sqlcmd를 사용하는 대신 BEGIN TRAN/ROLLBACK을 사용하는 것이 좋습니다.

롤백 명령이 트리거 실행 원인 명령문 시작 이후 변경 사항을 모두 실행 취소하더라도 이후 명령에 의한 변경 사항은 실행되지 않습니다.

TRIGGER BEGINS 

<INSERT INSERTED AND DELETED TABLES INTO TABLE VARIABLES, U'LL NEED THEM> 

BEGIN TRY 

BEGIN TRAN 

INSERT INTO AUDITTABLE SELECT * FROM @INSERTED 

COMMIT 

END TRY 

BEGIN CATCH 

ROLLBACK 

REDO ORIGINAL INSERT/UPDATE/DELETE USING TRIGGER TABLE VARIABLES (@INSERTED AND @DELETED) 

INSERT INTO AUDITERROS... 

END CATCH 

BEGIN TRAN -- THIS IS TO FOOL SQL INTO THINKING THERE'S STILL A TRANSACTION OPEN 

TRIGGER ENDS 
관련 문제