我有一个插入/更新/删除触发器,每次对特定表进行插入/更新/删除时,它会在AuditTable中插入一条新记录。如果在AuditTable中插入失败,我希望无论如何都要插入第一条记录,并将错误记录在另一个表“AuditErrors”中。
这是我到目前为止所做的事情,我尝试了许多不同的东西,但是如果触发器插入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
答案 0 :(得分: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 '+@@SERVERNAME+' -E -d '+DB_NAME()+' -Q "exec insertAudit @id='+cast(@id as varchar(20))+',@Info='''+@info+'''"';
begin try
exec @rc=sys.xp_cmdshell @cmd
select @rc;
end try
begin catch
select 0;
end catch;
end
GO
删除Audit表,它仍然完成原始事务。
干杯!
答案 1 :(得分:0)
您可以考虑使用BEGIN TRAN / ROLLBACK,而不是使用sqlcmd。
请注意,即使回滚命令将撤消自语句启动以来导致触发器触发的所有更改,但后续命令所做的任何更改都不会。
如果在审计表中插入数据的事务被回滚,那么您所要做的就是重复执行@sql中的代码:
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