日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

【转】了解SQL Server触发器及触发器中的事务

發布時間:2023/12/9 数据库 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】了解SQL Server触发器及触发器中的事务 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

引述


?

?????首先, 說下我寫篇文章的目的,我希望能把我對觸發器的理解,分享出來與你一起學習。如果你有對觸發器和事務的概念,有些了解,這篇文章,對你來說會是很簡單,或能讓你更進一步的了解觸發器里面的一些故事,和觸發器中事務個故事。在這邊文章里面,我不會從觸發器和事務的概念去講述,而是從常見的兩種觸發器類型(DML觸發器 & DDL觸發器)和After觸發器 &? Instead Of 觸發器的應用不同,開始說起它們,然后是說與事務有關的故事。如果,你有什么建議和意見,都可以通過文章后面的回復與我溝通,或者通過E-Mail方式,與 我交流;我的Email地址是:glal@163.com

???? 在下面的內容,用到一些SQL Server 觸發器和事務的一些術語,如果有些不明白的地方,可以查閱MSDN資料庫,或SQL Server本地幫助文檔:

  • DML觸發器(DML Triggers)
  • DDL觸發器(DDL Triggers)
  • 事務模式(Transaction modes)
  • 顯式事務(Explicit Transactions)
  • 自動提交事務(Autocommit Transactions)
  • 隱式事務(Implicit Transactions)
  • 批范圍的事務(Batch-scoped Transactions)

?

After觸發器?Vs?Instead Of觸發器

??????????? After 觸發器將在處理觸發操作(Insert、Update 或 Delete)、Instead Of 觸發器和約束之后激發。Instead Of是將在處理約束前激發,以替代觸發操作。下面兩張圖描述了After觸發器和Instead Of觸發器的執行先后順序。

?????????????

???? 圖1???????????????????????????????????????????????????????????????????????????? 圖2

???? 左邊的圖1,描述了After觸發器執行順序情況,我在這里通過一個簡單的例子來說明After觸發器的執行順序,以便能加深對左圖1 After觸發器的理解。

先創建表Contact

use tempdb Go if object_id('Contact') Is Not null Drop Table Contact Go Create Table Contact ( ID int Primary Key Identity(1,1), Name nvarchar(50), Sex nchar(2) Check(Sex In(N'F',N'M')) Default('M') ) Go

再創建After觸發器tr_Contact

use tempdb Go If Exists(Select 1 From sys.triggers Where name='tr_Contact') Drop Trigger tr_Contact Go Create Trigger tr_Contact On Contact After Insert As Select Name,Sex From Inserted /*顯示Inserted表的內容,用來判斷觸發器執行的先后順序*/ Go

然后Insert數據,判斷After觸發器的執行順序

use tempdb Go Insert Into Contact (Name,Sex) Values ('Bill','U') Go

這里,在沒有運行Insert語句之前,我們可以判斷,執行Insert過程會觸發Check錯誤,因為字段Sex的值必須是”F” Or “M”,而這里將要插入的是”U”.好了,再來看運行Insert語句后的情況。

本例子,只看到引發Check約束沖突的錯誤,而無法看到Inserted表的數據,說明一點就是,引起Check約束之前,不會引發After觸發器tr_Contact的操作。這就驗證了圖1的After觸發器執行順序情況。

???? 好了,接下來,我們再測試Instead Of觸發器 圖2的情況;我使用上邊建好的測試表Contact來舉例。

先修改觸發器tr_Contact內容,

use tempdb Go If Exists(Select 1 From sys.triggers Where name='tr_Contact') Drop Trigger tr_Contact Go Create Trigger tr_Contact On Contact Instead Of Insert As print '觸發器作代替執行操作' Insert Into Contact (Name,Sex) Select Name,Sex From Inserted /*代替觸發器外面的Insert行為*/ Go

再Insert數據,觀察SQL Server執行后的提示信息,

use tempdb Go Insert Into Contact (Name,Sex) Values ('Bill','U') Go

??

這里,看到,先是觸發器操作,再是Check約束處理。本例中,在觸發器里面使用一條Insert的語句來描述觸發器的代替執行操作,這SQL語句通過Select表Inserted得到觸發器外面Insert內容。當SQL Server執行到觸發器里面的Insert語句,才會引起Check約束處理.倘若,在觸發器tr_Contact沒有Insert的代替行為,那么就不會出現Check約束處理錯誤的信息(注:沒有Check錯誤信息,并不表示沒有作Check處理)。修改上邊的觸發器tr_Contact內容,做個簡易的驗證.

use tempdb Go If Exists(Select 1 From sys.triggers Where name='tr_Contact') Drop Trigger tr_Contact Go Create Trigger tr_Contact On Contact Instead Of Insert As print '觸發器作代替執行操作' Go use tempdb Go Insert Into Contact (Name,Sex) Values ('Bill','U') Go Select * From Contact

可以看到,Instead Of 觸發器tr_Contact內容沒有Insert的SQL語句,不會引發Check處理錯誤,而且檢查Insert動作后的結果,發現表Contact也沒有之前我們Insert的數據。這些足夠驗證了Instead Of觸發器的執行先后順序和代替執行操作。

DML 觸發器?Vs?DDL 觸發器


????? DML 觸發器在 Insert、Update 和 Delete 語句上操作,可以作為After 觸發器 和 Instead Of 觸發器。

?????DDL 觸發器對 Create、Alter、Drop 和其他 DDL 語句以及執行 DDL 式操作的存儲過程執行操作,只可作為After觸發器,不能Instead Of觸發器。

???? 前面的內容,有描述DML觸發器中的After & Instead Of觸發器內容,下面直接來看DDL的操作順序:

?????

???? 圖3.

???? 從圖3.可以知道,在DDL觸發器中,是沒有創建Inserted & Deleted過程的,我們通過簡單的例子去測試下。

???? 創建一個服務器范圍內的DDL觸發器,檢查有沒有Inserted 表,

use master Go If Exists(Select 1 From sys.server_triggers Where name='tr_createDataBase') Drop Trigger tr_createDataBase On All Server Go Create Trigger tr_createDataBase On All Server After Create_DataBase As Select * From inserted Go

執行創建數據庫SQL語句,

use master Go Create Database myDataBase On Primary (Name='MyDataBase_Data',Filename='E:\DATA\SQL2008DE01\MyDataBase_Data.mdf') Log On (Name='MyDataBase_Log',Filename='E:\DATA\SQL2008DE01\MyDataBase_Log.ldf') Go

返回錯誤信息,

使用上邊相同的方法,我們驗證DDL觸發器中,不會創建Deleted表;是否創建Deleted & Inserted,也可以認為是DDL觸發器與DML觸發器不同之處。在DLL觸發器與DML觸發器不同的一個重要特征是作用域,DML觸發器只能應用在數據庫層(Database Level)的表和視圖上,而DDL觸發器應用于數據庫層(Database Level)和服務器層(Server Level);DDL觸發器的作用域取決于事件。下面簡單描述下事件組的內容。

數據庫層事件主要包含:

  • DDL Table events: Create table, Alter table, Drop table
  • DDL view events : Create view, Alter view, Drop view
  • DDL trigger events :Create trigger, Drop trigger, Alter trigger
  • DDL synonym events: Create synonym, drop synonym
  • DDL Index events: Create index, Alter index, Drop Index
  • DDL Database level security events:
    • Create User, Drop user, Alter user
    • Create role, Drop role, Alter role
    • Create application role, Drop application role, Alter Application role
    • Create Schema, Drop Schema, Alter Schema
    • Grant database access, Revoke database access, Deny Database access
  • DDL Service broker events:
    • Create Message type, Alter Message type, Drop Message type
    • Create contract, Drop contract, Alter contract
    • Create Service, Alter service, Drop Service
    • Create route, Drop route, Alter route
  • 服務器層事件主要包含:

  • Create Database, Drop Database
  • Create Login, Drop Login, Alter Login
  • 觸發器和事務的故事


    ????? 在前面的幾個例子中,如DML觸發器例子,Insert 語句執行后,因為觸發器操作 或 Check處理錯誤,沒有把數據真正的插入到表Contact中。其實,當執行觸發器時,觸發器的操作好像有一個未完成的事務在起作用。 通過幾個例子來講解觸發器和事務的故事。

    創建一個表ContactHIST,用于對表Contact作Update Or Delete操作時,把操作前的數據Insert到表ContactHIST中。

    use tempdb Go if object_id('ContactHIST') Is Not null Drop Table ContactHIST Go Create Table ContactHIST ( ID int Primary Key Identity(1,1), ContactID int, Name nvarchar(50), Sex nchar(2), ActionType nvarchar(10) Check(ActionType In('Update','Delete')), LastUpdateDate datetime Default(getdate()) ) Go

    修改觸發器tr_Contact內容,

    use tempdb Go If Exists(Select 1 From sys.triggers Where name='tr_Contact') Drop Trigger tr_Contact Go Create Trigger tr_Contact On Contact After Update,Delete As Insert Into ContactHIST(ContactID,Name,Sex) Select ID,Name,Sex From deleted ? Rollback Tran ? Begin Tran Go

    測試數據,

    use tempdb Go Insert Into Contact (Name,Sex) Values ('Bill','F') Go --Update Update Contact Set Sex='M' Where Name='Bill' Go Select * From Contact Select * From ContactHIST Go

    測試結果:

    從上邊的測試情況,看出,Update Contact觸發tr_Contact觸發器操作,觸發器里面的Rollback Tran 動作導致了觸發器外面的Update語句執行回滾,而Rollback Tran 語句后面的Begin Tran語句,主要是應用于保持整個事務的完整性。為了更能理解這一過程,我模擬了一個觸發器中的事務開始結束過程。

    圖4.

    在SQL Server 2005 和 SQL Server 2008上面,可以看到如圖4.的效果。在低版本的SQL Server上,可能會出現錯誤提示情況,不管如何,在觸發器外面,SQL Server都會Rollback Tran。下面我做個錯誤提示的例子。

    修改觸發器tr_Contact內容

    use tempdb Go If Exists(Select 1 From sys.triggers Where name='tr_Contact') Drop Trigger tr_Contact Go Create Trigger tr_Contact On Contact After Update,Delete As Insert Into ContactHIST(ContactID,Name,Sex) Select ID,Name,Sex From deleted ? Rollback Tran ? --Begin Tran Go

    重新執行Update操作,

    use tempdb Go Update Contact Set Sex='M' Where Name='Bill' Go Select @@TRANCOUNT Go Select * From Contact Select * From ContactHIST Go

    在觸發器里面沒有Begin Tran語句動作,觸發器外面也能回滾操作。這里我們可以通過查詢表數據和@@Trancount來判斷。

    ???????? 其實,上面的例子,Update語句,是以自動提交事務(Autocommit Transactions)模式?開始執行的,觸發器里Rollback Tran后面,不管有沒有Begin Tran ,最后都會事務都會交回給SQL Server自動提交事務管理。當然,在DML觸發器中,你可以使用顯式事務(Explicit Transactions),或開啟隱式事務(Implicit Transactions)?來控制,當然你也可以應用于批范圍的事務(Batch-scoped Transactions)?中。這里,我通過開啟隱式事務(Implicit Transactions)?的例子來說,觸發器與事務的關系。

    修改觸發器tr_Contact的內容,

    use tempdb Go If Exists(Select 1 From sys.triggers Where name='tr_Contact') Drop Trigger tr_Contact Go Create Trigger tr_Contact On Contact After Update,Delete As Print N'觸發器里Insert 前,@@Trancount='+Rtrim(@@Trancount) ? Insert Into ContactHIST(ContactID,Name,Sex) Select ID,Name,Sex From deleted ? Print N'觸發器里Insert后,Rollback Tran 前,@@Trancount='+Rtrim(@@Trancount) ? Rollback Tran ? Print N'觸發器里Rollback Tran 后,@@Trancount='+Rtrim(@@Trancount) ? Begin Tran Go

    開啟隱式事務(Implicit Transactions)?來測試,

    use tempdb Go Set Implicit_transactions On /**/ Go Print N'Update Contact前,@@Trancount='+Rtrim(@@Trancount) ? Update Contact Set Sex='M' Where Name='Bill' Print N'Update Contact后,@@Trancount='+Rtrim(@@Trancount) ? Rollback Tran ? Print N'觸發器外面Rollback Tran 后,@@Trancount='+Rtrim(@@Trancount) Go Set Implicit_transactions Off /**/ Go ? Go Select * From Contact Select * From ContactHIST Go

    這里,你是否發現一個很有意思的問題,在觸發器理,執行Insert ContactHIST之前,@@Trancount=1,執行Insert后,@@Trancount還是為1,觸發器外面Update Contact后,@@Trancount就變成了2,。這里可以理解成,你在觸發器里面,發出一個Begin Tran,那么SQL Server 就會創建一個嵌套事務。當你在觸發器里面,在Rollback Tran后面屏蔽掉Begin Tran,就會出現錯誤3609,如,

    use tempdb Go If Exists(Select 1 From sys.triggers Where name='tr_Contact') Drop Trigger tr_Contact Go Create Trigger tr_Contact On Contact After Update,Delete As Print N'觸發器里Insert 前,@@Trancount='+Rtrim(@@Trancount) ? Insert Into ContactHIST(ContactID,Name,Sex) Select ID,Name,Sex From deleted ? Print N'觸發器里Insert后,Rollback Tran 前,@@Trancount='+Rtrim(@@Trancount) ? Rollback Tran ? Print N'觸發器里Rollback Tran 后,@@Trancount='+Rtrim(@@Trancount) ? Go

    這里,可以看到事務在觸發器中Rollback,又沒有開啟新的事務,導致整個批處理就中止,不會繼續執行觸發器外面的Rollback Tran操作。倘若,你在觸發器中使用Begin Tran …… Commit Tran格式,那么觸發器Commit Tran不會影響到外面的事務;下面描述三種常見觸發器中事務的情況:

    圖5.???????????????????????????????????????????????????????????????????????????? 圖6.?????????????????????????????????????????????????????????????????????????? 圖7.

    圖5.描述在觸發器中含有Begin Tran …… Commit Tran的情況,

    圖6.描述在觸發器中含有Save Tran?savepoint_name?……?Rollback Tran?savepoint_name 的情況,觸發器中的Rollback Tran 只會回滾指定的保存點,不會影響到觸發器外面的Commit Tran Or Rollback Tran操作。

    圖7.描述在觸發器中含有Rollback Tran的情況,不管觸發器里面有沒有Begin Tran,都會出現錯誤3609,中止批處理。

    ????注:DDL觸發器操作可以觸發器中回滾操作,可以使用命令如Rollback,但嚴重錯誤可能會導致整個事務自動回滾。不能回滾發生在 DDL 觸發器正文內的 Alter Database事件。在觸發器中使用Rollback … Begin Tran 可能會導致意想不到的結果,在沒有確認和測試情況下,請不要隨便在觸發器中直接使用Rollback …Begin Tran處理方式.特別是Create Database事件,在SQL Server 2008和SQL Server 2005環境下,產生的結果不同。

    Rollback …Begin Tran情況:

    Create Trigger ….

    As

    ……

    Rollback

    Begin Tran

    End

    ?

    小結


    ???? 回顧前文至后文,從After觸發器VsInstead Of 觸發器,說到DML觸發器 Vs DDL觸發器,再到觸發器中事務的故事。也許有些地方描述的有些模糊,有些地方只有一筆帶過;你在測試代碼過程中,可能發現有些地方與這里測試的情況不同,那可能是因為SQL Server版本的不同,導致一些測試結果不同。無論如何,只要你感覺對你了解觸發器,有些幫助,就OK了。

    轉載于:https://www.cnblogs.com/mo-beifeng/archive/2011/05/16/2048137.html

    總結

    以上是生活随笔為你收集整理的【转】了解SQL Server触发器及触发器中的事务的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。