所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路。
本篇是触发器专题,有很多触发器的问题。
1、关于触发器中回滚的问题。
在官方文档http://technet.microsoft.com/zh-cn/library/ms181299.aspx中“互操作性”段落中有这么一句:
触发器继续执行 ROLLBACK 语句之后的所有其余语句。 如果这些语句中的任意语句修改数据,则不回滚这些修改。 执行其余的语句不会激发嵌套触发器。
其中“执行其余的语句不会激发嵌套触发器”,是否意味着在回滚操作后面的语句如果继续执行的话,后面语句触发的触发器就不会执行了。比如后面的语句有针对一个表的update操作,而这张表又有update的触发器,这个时候update会执行成功,但触发器不会执行?
但是很奇怪,我做了一个实验,发现,即使是嵌套触发器,也能够被触发,和微软文档上说的不一样。
从下面的insert时的输出,可以看出,在触发器中rollback之后的语句,是可以执行的,另外,update另一个表的操作也执行成功,并且触发了触发器。
- --drop table t1
- --drop table t2
-
- create table t1(id int)
- create table t2(id int)
-
- insert into t2
- values(100)
- go
-
- create trigger dbo.trigger_t1
- on t1
- for insert
- as
-
- rollback;
-
- select ‘这是rollback之后的语句,这里能执行‘
-
- update t2
- set id = 1;
- go
-
-
-
- create trigger dbo.trigger_t2
- on t2
- for update
- as
-
- select ‘这是t2的update触发器,这里能执行‘
-
- go
-
-
- --插入数据
- insert into t1
- values(1)
- /*
- 这是rollback之后的语句,这里能执行
- 这是t2的update触发器,这里能执行
- 消息 3609,级别 16,状态 1,第 3 行
- 事务在触发器中结束。批处理已中止。
- */
-
- --没有记录
- select * from t1
-
-
- select * from t2
- /*
- id
- 1
- */
2、触发器的错误处理
http://bbs.csdn.net/topics/390637035
我在A表写了个触发器 插入后执行,是向B表插入一条记录
- USE [test]
- GO
- SET ANSI_NULLS ON
- GO
- SET QUOTED_IDENTIFIER ON
- GO
- ALTER TRIGGER [dbo].[tba_delete]
- ON [dbo].[tba]
- AFTER INSERT
- AS
- BEGIN
- SET NOCOUNT ON;
- insert into test.dbo.tbb(title,info) values(‘title‘,‘info‘);
- END
insert into test.dbo.tbb(id,title,info) values(1,‘title‘,‘info‘);
我的解法:
- USE [test]
- GO
-
- SET ANSI_NULLS ON
- GO
-
- SET QUOTED_IDENTIFIER ON
- GO
-
-
- create table [tba](title varchar(20),info varchar(20))
-
- create table tbb(title varchar(20),info varchar(20))
-
-
- --创建一个存放错误信息的表
- create table tb_error_message
- (
- obj_name nvarchar(30),
- obj_type nvarchar(15),
- err_msg nvarchar(100),
- err_date datetime
- )
- go
-
- drop trigger tba_delete
- go
-
- create TRIGGER [dbo].[tba_delete]
- ON [dbo].[tba]
- AFTER INSERT
- AS
- BEGIN
- SET NOCOUNT ON;
-
- begin try
- --这里模拟插入title列的数据长度,超过了定义时的20
- insert into test.dbo.tbb(title,info) values(‘title1111111111111111111‘,‘info‘);
- end try
-
- begin catch
- --错误了就回滚
- rollback;
- insert into tb_error_message
- values(‘tba_delete‘,‘trigger‘,error_message(),getdate())
-
- end catch
-
- END
- go
-
- insert into tba
- values(‘11‘,‘11‘)
- /*
- 消息 3930,级别 16,状态 1,过程 tba_delete,第 16 行
- 当前事务无法提交,而且无法支持写入日志文件的操作。请回滚该事务。
- 语句已终止。
- */
-
-
- --查询出错的信息
- select *
- from tb_error_message
- /*
- obj_name obj_type err_msg err_date
- tba_delete trigger 将截断字符串或二进制数据。 2013-11-08 12:32:16.750
- */
3、忽略触发器中的错误
http://bbs.csdn.net/topics/390623172
我的情况是这样的: 当向A表插入数据时,需要向某用户发送信息通知,由于插入数据方是第三方软件做的,我控件不了,所以我在A表加个触发器来实现,现在问题是发送信息这里的错误是可以忽略的,就是说假如发送失败不影响数据的插入,请问我在触发器里如何忽略错误,让事务继续执行.
我的思路是:
- --先保存一个事务点
- SAVEPOINT xxx
-
- begin try
- --或者是调用存储过程,或者就直接写代码
- exec 发送信息的存储过程
- end try
- begin catch
- select ‘执行失败‘
- --一旦出错,只是回滚到上面的事务点,继续执行
- ROLLBACK [WORK] TO SAVEPOINT xxx
- end catch
-
- --其他代码
原文:https://www.cnblogs.com/lonelyxmas/p/12020022.html