这是一个奇怪的问题:是否可以在表中进行免回滚插入?
这是场景: 我们有一个可以做事的触发器。
有时,此触发器将调用RAISERRROR()
。然后外部事务回滚。
但是,在触发器中,我想将值插入到日志记录表中,并且在回滚期间(如果愿意的话)可以免除事务处理。
答案 0 :(得分:1)
您可以使用try-catch
捕获异常并将其传递/抛出外部范围,该范围必须存在相同的内容。顺便说一下,这允许您收集call-stack
。如果仅通过storedprocs工作,则可以实施此解决方案。每个proc必须具有这样的模式:
begin try
end try
begin catch
if @@trancount > 0
rollback
insert into <log> (...)
values (...)
throw
end catch
因此最顶层的过程将成功向日志表中插入一行。
缺点:
优点:
反馈:
您可以构建一个确实插入到日志表中的CLR组件,仅此而已...但是!可以指定一个单独的连接,以通过该单独的连接使此程序集与db一起使用。这意味着-在单独的范围内。因此,无论在何种事务范围内,都将从事务内调用此程序集的方法,但是将执行该程序集。
所以,而不是:
using(SqlConnection connection = new SqlConnection("context connection=true"))
只需指定常规连接字符串即可。调用之后-抛出带有修改后的ERROR_STATUS
的异常,以避免再次记录相同的错误。
begin try
end try
begin catch
if @@trancount > 0
rollback
if @@ERRROR_STATUS != @done_with_logging
exec asm.log(...)
raiserror @err_msg, @severity, @done_with_logging
end catch
缺点:
优点:
反馈:
这个简单的语句(实际上只是附加选项WITH LOG
)会将您想要的任何错误消息写入SQL SERVER事件日志:
RAISERROR(...) WITH LOG
这不是应该使用SQL SERVER日志的方法,但这是记录重要内容(解决问题)的最快方法。可以在SSMS代理的窗口中查看已记录的事件。
缺点:
优点:
反馈:
{一个关于基于DML触发器构建系统的基于意见的讨论的场所}
在我看来,您没有在项目中使用存储的proc而是执行临时查询。如果您的后端应用程序带有ORM或类似的东西,请使用它编写日志。而且,也许此后端应用程序是在触发器内部执行操作的更好场所。
如果您的项目是不带appserver / backend应用程序的客户端-服务器应用程序,而您仅有的是即席查询和触发器,则没有太多数据要记录。没有调用堆栈(在服务器端)。而且很难确定您(用户,应用程序)是如何发生此特定异常的。因此,在这种情况下,登录客户端可能会更有用。
答案 1 :(得分:0)
如果创建一个表变量然后插入到该变量中-它将不会包含在回滚中,因此可以将其内容转储到永久表中。
例如
declare @tab table (msg varchar(255))
BEGIN TRY
BEGIN TRANSACTION
select 1+2
INSERT @tab values ('first step complete')
SElect 1/0
INSERT @tab values ('2nd step complete')
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
SELECT * FROM @tab
END CATCH
答案 2 :(得分:0)
过段时间再写。您可以使用代替触发器:
create table t
(
i int,
s varchar(10)
)
go
create table t2
(
i int,
s varchar(10)
)
go
create table tlog
(
i int,
s varchar(10)
)
go
alter trigger tt on t
INSTEAD OF INSERT
AS
BEGIN
rollback transaction
raiserror ('something went wrong', 16, 2)
insert tlog (i,s)
select i, s
from inserted
END
go
truncate table t
truncate table t2
truncate table tlog
go
select * from t
select * from t2
select * from tlog
go
begin transaction
insert t2 (i,s) values (1, 'abc')
insert t (i,s) values (1, 'abc')
commit transaction
go
select * from t
select * from t2
select * from tlog
给出以下输出:
我是
(0 行受影响)
我是
(0 行受影响)
我是
(0 行受影响)
(1 行受影响) 消息 50000,级别 16,状态 2,程序 tt,第 7 行 出了点问题
(1 行受影响) 消息 3609,级别 16,状态 1,第 4 行 事务在触发器中结束。该批次已中止。 我是
(0 行受影响)
我是
(0 行受影响)
我是
1 abc
(1 行受影响)