触发器学习
After 触发器将在处理触发操作(Insert、Update 或 Delete)、Instead Of 触发器和约束之后激发。Instead Of是将在处理约束前激发,以替代触发操作。
After触发器在触发时操作已影响表中数据,Instead of 触发器触发时操作未影响数据表中数据。
不存在DDL 类型的Instead of 触发器,在DDL触发器创建时可以使用Instead表和Deleted表,但是会引发运行时异常。
可以在存储过程或触发器中执行 ROLLBACK TRANSACTION 或 COMMIT TRANSACTION Transact-SQL 语句,但这样可能会导致错误。(MSDN)
应该在触发器中尽量避免事务会滚操作,测试如下:
--创建测试环境
USE tempdb
GO
CREATE TABLE dbo.TRTest
(
ID INT
)
GO
CREATE TABLE dbo.TRTestHistory
(
ID INT,
InsertDate datetime default GETDATE()
);
-- 创建INSTEAD OF 触发器
-- 第一次向dbo.TRTestHistory插入数据,然后回滚事务
-- 第二次向dbo.TRTestHistory插入数据,然后提交事务
CREATE TRIGGER TR_TRTest ON dbo.TRTest
INSTEAD OF INSERT
AS
BEGIN
BEGIN TRAN
Insert into dbo.TRTestHistory(ID)
SELECT ID FROM inserted
ROLLBACK TRAN
BEGIN TRAN
Insert into dbo.TRTestHistory(ID)
SELECT ID+100 FROM inserted
COMMIT TRAN
END
--清理表中数据
TRUNCATE TABLE dbo.TRTest
TRUNCATE TABLE dbo.TRTestHistory
--尝试插入数据,触发TR_TRTest触发器
INSERT INTO dbo.TRTest
SELECT 1
--检查数据表中数据
SELECT * FROM dbo.TRTest
SELECT * FROM dbo.TRTestHistory
结果:插入操作提示错误“The transaction ended in the trigger. The batch has been aborted.”,但dbo.TRTestHistory表中有数据插入。
-- 创建INSTEAD OF 触发器
-- 第一次向dbo.TRTestHistory插入数据,然后回滚事务
-- 第二次向dbo.TRTestHistory插入数据,然后提交事务
ALTER TRIGGER TR_TRTest ON dbo.TRTest
INSTEAD OF INSERT
AS
BEGIN
BEGIN TRAN TR1
Insert into dbo.TRTestHistory(ID)
SELECT ID FROM inserted
ROLLBACK TRAN TR2
BEGIN TRAN
Insert into dbo.TRTestHistory(ID)
SELECT ID+100 FROM inserted
COMMIT TRAN
END
--清理表中数据
TRUNCATE TABLE dbo.TRTest
TRUNCATE TABLE dbo.TRTestHistory
--尝试插入数据,触发TR_TRTest触发器
INSERT INTO dbo.TRTest
SELECT 1
--检查数据表中数据
SELECT * FROM dbo.TRTest
SELECT * FROM dbo.TRTestHistory
结果:插入时异常“Cannot roll back TR1. No transaction or savepoint of that name was found. The statement has been terminated. ”,
但dbo.TRTestHistory表中没有数据
-- 创建AFTER触发器
-- 第一次向dbo.TRTestHistory插入数据,然后回滚事务
-- 第二次向dbo.TRTestHistory插入数据,然后提交事务
ALTER TRIGGER TR_TRTest ON dbo.TRTest
AFTER INSERT
AS
BEGIN
BEGIN TRAN TR1
Insert into dbo.TRTestHistory(ID)
SELECT ID FROM inserted
ROLLBACK TRAN TR1
BEGIN TRAN
Insert into dbo.TRTestHistory(ID)
SELECT ID+100 FROM inserted
COMMIT TRAN
END
--清理表中数据
TRUNCATE TABLE dbo.TRTest
TRUNCATE TABLE dbo.TRTestHistory
--尝试插入数据,触发TR_TRTest触发器
INSERT INTO dbo.TRTest
SELECT 1
--检查数据表中数据
SELECT * FROM dbo.TRTest
SELECT * FROM dbo.TRTestHistory
结果:插入时异常“Cannot roll back TR1. No transaction or savepoint of that name was found. The statement has been terminated. ”,
但dbo.TRTestHistory表中没有数据
总结:大部分情况下在触发器中使用ROLLBACK TRAN会导致包括触发器内部以及引发触发器激活的操作在内的事务会滚,但部分情况下触发器ROLLBACK TRAN后续的操作仍能操作成功。