日期:2014-05-17  浏览次数:20848 次

SQL 2005 ,触发器里带rollback 或者commit语句的问题
本帖最后由 zhangyangziwo 于 2013-09-02 15:47:57 编辑
大家好,
我公司程序的数据库由SQL2000升级到SQL 2005,以前正常的操作的功能,现在报一些错误,比如:
消息 3609,级别 16,状态 1,第 2 行
事务在触发器中结束。批处理已中止。

经过搜索,说是2005里的触发器不让带rollback或者commit语句。
下边是MSDN,对此问题的描述,只说了原理,没说咋解决。
http://msdn.microsoft.com/zh-cn/library/ms187844(v=sql.90).aspx

搜到的解决方法:
1、rollback 后边带 begin tran,有可能破坏业务逻辑。
2、不用rollback等,用raiserror发送错误码,在调用它的语句里控制事务。
3、先判断一下@@tran,如果有事务就不再加这些语句。

不知道那种正确,或者有更正确的处理方法。

我需要将sql2000里的触发器都更改过来,更好是有能兼容2000和2005的写法。
先谢谢诸位
事务 SQL2005?3609?触发器 数据库

------解决方案--------------------
这种错误,一般是在嵌套调用是发生的。举例:
--分析:
ALTER PROC up_test3
AS
PRINT 'begin'
BEGIN TRAN
COMMIT TRAN  
PRINT 'end'
go

ALTER PROC up_test2
AS
ROLLBACK --#3.注意:一个嵌套存储过程中的任何一个rollback语句,都会回滚到最顶级的父的begin tran,这儿的例子就是#1步的BEGIN TRAN
--RAISERROR('',16,1)
GO

ALTER PROC up_test1
AS
BEGIN TRAN --#1.显示开启一个事务
EXEC up_test2 --#2.调用子存储过程(相当于你的触发器)
PRINT '^_^' --#4.注意,这时候。SQL并不会在#3步就终止执行,还是会继续往下走
EXEC up_test3 --#5.调用up_test3,正常调用.
SELECT @@trancount
COMMIT --#6.当执行到这儿时,所有ROLLBACK之前的BEGIN TRAN都已经被ROLLBACK撤销了.所以就没有与这个COMMIT对应的BEGIN TRAN了,所以就报错
GO

EXEC UP_TEST1
/*
消息 266,级别 16,状态 2,过程 up_test2,第 0 行
EXECUTE 后的事务计数指示 BEGIN 和 COMMIT 语句的数目不匹配。上一计数 = 1,当前计数 = 0。
^_^
begin
end
消息 3902,级别 16,状态 1,过程 up_test1,第 7 行
COMMIT TRANSACTION 请求没有对应的 BEGIN TRANSACTION。
*/

--解决方案:
--1、rollback 后边带 begin tran,有可能破坏业务逻辑。这个方法,其实是可行的,楼主为什么说它会破坏业务逻辑呢?
--2、不用rollback等,用raiserror发送错误码,在调用它的语句里控制事务。 这个方法也可行,就是要注意在最外层一定要有异常捕获,捕获后,再统一ROLLBACK.既然已经是2005,个人推荐使用这种方法。
BEGIN TRY
BEGIN TRAN
EXEC UP_TEST1
COMMIT TRAN
END try
begin CATCH
rollback
END catch
--3、先判断一下@@tran,如果有事务就不再加这些语句。 这个我没理解什么意思。