更高难度问题:关于事务和触发器的一些矛盾

spotboy 2003-12-02 02:30:02
假设当前事务中包含一系列对表A的操作,同时表A有一个与之关联的触发器,那么这个触发器是在这个事务操作结束以后才被触发,还是在事务进行中就被触发了呢?
...全文
29 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
txlicenhe 2003-12-02
  • 打赏
  • 举报
回复
楼上讲完了。
luyongning 2003-12-02
  • 打赏
  • 举报
回复
SQL SERVER的幫助中有如下說明:
預存程序與觸發程序中的復原
如果 @@TRANCOUNT 在預存程序 (Stored Procedure) 完成時的值與預存程序執行時的值不同,便產生資訊式的錯誤 266。這個錯誤在相同條件下的觸發程序 (Trigger) 中不會產生。

266 錯誤是在 @@TRANCOUNT 大於或等於 1,且預存程序在執行 ROLLBACK TRANSACTION 或 ROLLBACK WORK 陳述式而被呼叫時產生。這是因為 ROLLBACK 將所有尚未處理完畢的交易復原,並將 @@TRANCOUNT 降為 0,而此值低於呼叫程序時的值所致。

如果 ROLLBACK TRANSACTION 是在觸發程序中發出:

在目前交易中進行至該點的所有資料修改都會復原,包括觸發程序所做的修改。


觸發程序繼續執行 ROLLBACK 陳述式之後的其餘陳述式。這其中若有任何修改資料的陳述式,修改動作並不會復原。這些剩餘陳述式的執行並不會引發巢狀觸發程序。


引發觸發程序的陳述式之後的批次中的任何陳述式都不會執行。


觸發程序中的 ROLLBACK 關閉,並把包含引發觸發程序之陳述式的批次中宣告及開啟的資料指標 (Cursor) 全部取消配置。其中包括宣告及開啟於由引發觸發程序之批次所呼叫的預存程序中的資料指標。在引發觸發程序的批次之前的批次中宣告的資料指標只會關閉,但若有下列情況則 STATIC 或 INSENSITIVE 資料指標會保持開啟:


CURSOR_CLOSE_ON_COMMIT 設定為 OFF。


靜態資料指標為同步,或為完整填入的非同步 (Asynchronous) 資料指標。
觸發程序的運作一直像是在執行觸發程序時,會受到尚未處理完畢的交易影響一樣。引發觸發程序的陳述式如果是在隱含交易 (Implicit Transaction) 或外顯交易 (Explicit Transaction) 中,則這種情形永遠為真。自動認可模式亦同。當陳述式開始執行於自動認可模式時,隱含的 BEGIN TRANSACTION 便允許陳述式在遇到錯誤時,將自己產生的一切修改復原。這個隱含的交易不會影響到批次中的其他陳述式,因為它會在陳述式完成時被認可或復原。但是,當呼叫某個觸發程序時,此隱含的交易仍然有影響。

這表示一旦在觸發程序中提交 BEGIN TRANSACTION 陳述式則實際上便開始巢狀交易。由於在復原巢狀交易時,會忽略巢狀的 BEGIN TRANSACTION 陳述式,因此在觸發程序中提交的 ROLLBACK TRANSACTION,會略過觸發程序本身所提交的 BEGIN TRANSACTION 陳述式而永遠復原。ROLLBACK 復原至最外側的 BEGIN TRANSACTION。

您必須在觸發程序中使用 SAVE TRANSACTION 陳述式來進行部分復原,即使這個陳述式總是在自動認可模式下被呼叫。下列觸發程序說明了這一點:

CREATE TRIGGER TestTrig ON TestTab FOR UPDATE AS
SAVE TRANSACTION MyName
INSERT INTO TestAudit
SELECT * FROM inserted
IF (@@error <> 0)
BEGIN
ROLLBACK TRANSACTION MyName
END

這同時也會影響到觸發程序中,接續 BEGIN TRANSACTION 陳述式的 COMMIT TRANSACTION 陳述式。由於 BEGIN TRANSACTION 啟動巢狀交易,後續的 COMMIT 陳述式便僅套用於巢狀交易。如果 ROLLBACK TRANSACTION 陳述式是在 COMMIT 之後執行,ROLLBACK 則將一切都復原到最外側的 BEGIN TRANSACTION。下列觸發程序說明了這一點:

CREATE TRIGGER TestTrig ON TestTab FOR UPDATE AS
BEGIN TRANSACTION
INSERT INTO TrigTarget
SELECT * FROM inserted
COMMIT TRANSACTION
ROLLBACK TRANSACTION

上述觸發程序永遠不會插入到 TrigTarget 資料表。BEGIN TRANSACTION 啟動的會是巢狀交易。COMMIT TRANSACTION 僅認可巢狀交易,而接續的 ROLLBACK TRANSACTION 則將一切都復原到最外層的 BEGIN TRANSACTION。
w_rose 2003-12-02
  • 打赏
  • 举报
回复
zjcxc(邹建)说的对,这个事务中任何rollback,不论它出现在存储过程中,还是触发器中,或者是一些运行时才能发现的概念错误(例如视图定义错误),都会将事务中所有被改编的数据回滚。

事务中,一旦遇到回滚,虽然程序代码执行了但是它没有能够保留下操作结果,又有什么可为程序担心的?这正是“事务处理”需要的能力。
mywhsw 2003-12-02
  • 打赏
  • 举报
回复
还真是,哈哈
w_rose 2003-12-02
  • 打赏
  • 举报
回复
你这个题目起得也太唬人了!!!!

触发器是在执行修改记录的SQL命令时被触发,而这个命令当然是在事务之中。
zjcxc 2003-12-02
  • 打赏
  • 举报
回复
触发器的事务是在你自己开启事务的内层.属于内层(嵌套)事务,而不是并列事务.
zjcxc 2003-12-02
  • 打赏
  • 举报
回复
当然不是,事务嵌套的处理是这样的.

如果外层的事务失败,则在它里面的事务也一齐失败.

lvltt 2003-12-02
  • 打赏
  • 举报
回复
认真学习、、、
mywhsw 2003-12-02
  • 打赏
  • 举报
回复
那么岂不是乱了!如果事务失败了,触发器还是被触发了,就违背了事务的概念了,除非事务失败的时候触发器会被自动的回滚,请zjcxc(邹建) 解释
zjcxc 2003-12-02
  • 打赏
  • 举报
回复
从上面的测试结果可以看到:

开始事务处理:

插入数据的时候,触发器被触发
打印出: 插入处理触发器

然后接着进行事务中的第二条语句
打印出: 插入处理

然后再提交事务
mywhsw 2003-12-02
  • 打赏
  • 举报
回复
???!!!关注!
zjcxc 2003-12-02
  • 打赏
  • 举报
回复
--下面是例子(需要在查询分析器中进行)

--创建测试表
create table tb(id int)
go
--创建触发器
create trigger t_insert on tb
for insert
as
print '插入处理触发器'
go

--事务处理
begin tran
insert into tb values(1)
print '插入处理'
commit tran

go
--删除测试表
drop table tb

/*--测试结果

插入处理触发器

(所影响的行数为 1 行)

插入处理

--*/
mywhsw 2003-12-02
  • 打赏
  • 举报
回复
肯定是提交事务以后才触发,因为事务的概念是要么全成功,要么全失败,触发器包含在事务里
zjcxc 2003-12-02
  • 打赏
  • 举报
回复
事务进行中就会触发触发器,而不是事务结束时.

22,207

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧