觸發(fā)器(trigger)是SQL server 提供給程序員和數(shù)據(jù)分析員來保證數(shù)據(jù)完整性的一種方法,它是與表事件相關(guān)的特殊的存儲過程,它的執(zhí)行不是由程序調(diào)用,也不是手工啟動,而是由事件來觸發(fā),比如當對一個表進行操作( insert,delete, update)時就會激活它執(zhí)行。觸發(fā)器經(jīng)常用于加強數(shù)據(jù)的完整性約束和業(yè)務(wù)規(guī)則等。 觸發(fā)器可以從 DBA_TRIGGERS ,USER_TRIGGERS 數(shù)據(jù)字典中查到。SQL3的觸發(fā)器是一個能由系統(tǒng)自動執(zhí)行對數(shù)據(jù)庫修改的語句。
觸發(fā)器可以查詢其他表,而且可以包含復(fù)雜的SQL語句。它們主要用于強制服從復(fù)雜的業(yè)務(wù)規(guī)則或要求。例如:您可以根據(jù)客戶當前的帳戶狀態(tài),控制是否允許插入新訂單。
觸發(fā)器也可用于強制引用完整性,以便在多個表中添加、更新或刪除行時,保留在這些表之間所定義的關(guān)系。然而,強制引用完整性的最好方法是在相關(guān)表中定義主鍵和外鍵約束。如果使用數(shù)據(jù)庫關(guān)系圖,則可以在表之間創(chuàng)建關(guān)系以自動創(chuàng)建外鍵約束。
觸發(fā)器與存儲過程的唯一區(qū)別是觸發(fā)器不能執(zhí)行EXECUTE語句調(diào)用,而是在用戶執(zhí)行Transact-SQL語句時自動觸發(fā)執(zhí)行。
分類

DML觸發(fā)器
當數(shù)據(jù)庫中表中的數(shù)據(jù)發(fā)生變化時,包括insert,update,delete任意操作,如果我們對該表寫了對應(yīng)的DML觸發(fā)器,那么該觸發(fā)器自動執(zhí)行。DML觸發(fā)器的主要作用在于強制執(zhí)行業(yè) 務(wù)規(guī)則,以及擴展Sql Server約束,默認值等。因為我們知道約束只能約束同一個表中的數(shù)據(jù),而觸發(fā)器中則可以執(zhí)行任意Sql命令。
DDL觸發(fā)器
它是Sql Server2005新增的觸發(fā)器,主要用于審核與規(guī)范對數(shù)據(jù)庫中表,觸發(fā)器,視圖等結(jié)構(gòu)上的操作。比如在修改表,修改列,新增表,新增列等。它在數(shù)據(jù)庫結(jié)構(gòu)發(fā)生變化時執(zhí)行,我們主要用它來記錄數(shù)據(jù)庫的修改過程,以及限制程序員對數(shù)據(jù)庫的修改,比如不允許刪除某些指定表等。
登錄觸發(fā)器
登錄觸發(fā)器將為響應(yīng) LOGIN 事件而激發(fā)存儲過程。與 SQL Server 實例建立用戶會話時將引發(fā)此事件。登錄觸發(fā)器將在登錄的身份驗證階段完成之后且用戶會話實際建立之前激發(fā)。因此,來自觸發(fā)器內(nèi)部且通常將到達用戶的所有消息(例如錯誤消息和來自 PRINT 語句的消息)會傳送到 SQL Server 錯誤日志。如果身份驗證失敗,將不激發(fā)登錄觸發(fā)器。
約束與觸發(fā)器有何區(qū)別
在SQL Server數(shù)據(jù)庫中提供了兩種主要機制來強制使用業(yè)務(wù)規(guī)則和數(shù)據(jù)完整性,它們是SQL Server約束和觸發(fā)器。觸發(fā)器其實就是一個特殊類型的存儲過程,可以在執(zhí)行某個操作時自動觸發(fā)。觸發(fā)器與約束都可以實現(xiàn)數(shù)據(jù)的一致性。那么他們在使用的過程中,有哪些差異呢?
約束和觸發(fā)器在特殊情況下各有優(yōu)勢。
約束主要被用于強制數(shù)據(jù)的完整性,約束也能提供比觸發(fā)器更好的性能。然而在所能完成的操作,以及完成工作時所能使用約束是有限制的。觸發(fā)器則常被用于驗證業(yè)務(wù)規(guī)則,或是更復(fù)雜的數(shù)據(jù)驗證,然而可以對數(shù)據(jù)的其他地方的數(shù)據(jù)完成更深入的更新,約束只能對其所在表中的數(shù)據(jù),或是在設(shè)計時輸入的特定數(shù)據(jù)進行驗證。這同觸發(fā)器形成對比,觸發(fā)器可以跨越數(shù)據(jù)庫甚至服務(wù)器,可以對任何在設(shè)計時設(shè)置的數(shù)據(jù),或從任何表上的其他行為所收集的數(shù)據(jù)進行檢查。如果所需的訪問權(quán)限被給予所有包含的對象,就可以使用觸發(fā)器的這些功能。
簡單的來說,觸發(fā)器可以實現(xiàn)約束的一切功能。但是在考慮數(shù)據(jù)一致性問題的時候,首先要考慮通過約束來實現(xiàn)。如果約束無法完成的功能,則再通過觸發(fā)器來解決。兩者從功能上來說,他們的關(guān)系如下圖所示:

觸發(fā)器可以包含使用SQL代碼的復(fù)雜處理邏輯。如果單從功能上來說,觸發(fā)器可以實現(xiàn)約束的所有功能。但是由于其自身的種種缺陷,其往往不是實現(xiàn)數(shù)據(jù)一致性等特定功能的首選解決方案??偟膩碚f 只有在約束無法實現(xiàn)特定功能的情況下,才考慮通過觸發(fā)器來完成。這只是在處理約束與觸發(fā)器操作過程中的一個基本原則。對于它們兩個具體的差異在下面也進行了比較詳細的闡述。
區(qū)別一:錯誤信息的管理上。
當違反系統(tǒng)的SQL Server約束規(guī)則時,需要向用戶返回一定的錯誤信息,方便用戶進行排錯。約束與觸發(fā)器在遇到問題時都可以返回給用戶一定的錯誤信息。但是,約束只能夠通過標準化的系統(tǒng)錯誤信息來傳遞錯誤消息。如果應(yīng)用程序需要使用自定義消息和較為復(fù)雜的錯誤處理機制,則必須要使用觸發(fā)器才能夠完成。如現(xiàn)在數(shù)據(jù)庫中有一張產(chǎn)品信息表。為了保證產(chǎn)品的唯一性,要求產(chǎn)品的編號必須唯一。如果用戶輸入的產(chǎn)品編號跟企業(yè)現(xiàn)有的產(chǎn)品編號有重復(fù)的話,這條產(chǎn)品信息就不能夠被保存。從技術(shù)上來說,約束與觸發(fā)器都可以實現(xiàn)這個需求。但是,當違反這個唯一性規(guī)則時,他們提供的錯誤信息是不同的。
如利用約束來實現(xiàn)這個唯一性控制,那么當用戶輸入重復(fù)的編號時,則系統(tǒng)會提示違反了唯一性規(guī)則,不允許保存。但是光憑這條消息的話,可能用戶還不能夠馬上了解是怎么回事情。有時候程序員希望能夠返回更加具體的信息。這時候就需要用到觸發(fā)器了。因為只有觸發(fā)器可以返回數(shù)據(jù)庫管理員自定義的錯誤信息;而且還可以實現(xiàn)比較復(fù)雜的邏輯控制。而約束只能夠范圍系統(tǒng)定義的標準錯誤信息。
區(qū)別二:性能上的差異分析。
相信大家看了下面的例子肯定會對它們在性能上存在的差異有進一步的了解。
如現(xiàn)在有兩張表,分別為銷售訂單頭與銷售訂單行。在銷售訂單中有一個訂單ID,它是這張表的主鍵,也是銷售訂單行表的外鍵。現(xiàn)在如果更改了銷售訂單頭表的主鍵的值,那么必須要保證銷售訂單行表中訂單ID的值也隨之更改。否則的話,銷售訂單頭表與銷售訂單行表就無法對應(yīng)起來。此時觸發(fā)器與約束都可以實現(xiàn)類似的功能。觸發(fā)器可以將銷售訂單頭ID的更改通過級聯(lián)更新的功能傳播給數(shù)據(jù)庫中其他相關(guān)的表,實現(xiàn)級聯(lián)更新。約束也可以實現(xiàn)類似的功能。而且通常情況下,通過級聯(lián)引用完整性約束可以更有效的執(zhí)行這個級聯(lián)更新。如當上面這個更改發(fā)生后,觸發(fā)器可以禁止或回滾違反引用完整性的更改,從而取消所嘗試的數(shù)據(jù)修改。當更改外鍵且新值與其主鍵不匹配時,這個的觸發(fā)器將生效。但是,數(shù)據(jù)庫中有一個現(xiàn)成的解決方案,即FOREIGN KEY 約束通常用于此目的。如果觸發(fā)器表上存在約束,則在 INSTEAD OF 觸發(fā)器執(zhí)行后但在 AFTER 觸發(fā)器執(zhí)行前檢查這些約束。如果違反了約束,則回滾 INSTEAD OF 觸發(fā)器操作并且不執(zhí)行 AFTER 觸發(fā)器。
在網(wǎng)上查了一下遇到這種情況后,往往有兩種處理方式。一是如果要更改的主鍵在其他表中已經(jīng)存在的話,那么就不允許其進行更改,系統(tǒng)會拒絕保存或者回滾用戶的更改操作。二是如果要更改的主鍵信息在其他表中已經(jīng)存在相關(guān)的記錄,而數(shù)據(jù)庫管理員又允許其更改的話,為了保證數(shù)據(jù)的一致性,就要出發(fā)級聯(lián)更新的功能。讓數(shù)據(jù)庫系統(tǒng)在更改主鍵的同時自動更新其他表中的相關(guān)信息。無論采取哪種方式,從性能上來說,約束的執(zhí)行性能都要高一點。而且系統(tǒng)本身就提供了一些約束規(guī)則,如級聯(lián)引用完整性約束的等等。故也省去了管理員寫觸發(fā)器代碼的工作量。不過有一點值得說明的是,雖然約束的執(zhí)行性能比較高,但是其向用戶提供的錯誤信息確實非常有限的。如上面第一點所說,系統(tǒng)只提供了一些標準的錯誤信息。如果管理員需要向用戶提供比較詳細的錯誤信息,則需要通過觸發(fā)器的自定義錯誤信息來實現(xiàn)。故在用戶的友好性與數(shù)據(jù)庫的執(zhí)行性能之間,數(shù)據(jù)庫管理員需要做出一個均衡。
區(qū)別三:管理維護的工作量。
由于約束基本上都是數(shù)據(jù)庫現(xiàn)成的解決方案。無論是索引約束還是外鍵約束,還是check約束。往往在數(shù)據(jù)庫系統(tǒng)中已經(jīng)有了現(xiàn)成的解決方案。數(shù)據(jù)庫管理員通過直接引用這些解決方案即可以實現(xiàn)特定的功能,而不用再費力的編寫觸發(fā)器來實現(xiàn)。如要實現(xiàn)表中某個字段的唯一性約束,則只需要直接在這個字段上啟用unique約束即可。從而省去了編寫觸發(fā)器代碼的時間。所以通常來說,觸發(fā)器的維護工作量要比約束來的多。因為觸發(fā)器中系統(tǒng)沒有現(xiàn)成的可以引用,而都需要數(shù)據(jù)庫管理員通過實際清理來進行編寫。如果不熟悉編制的話,還很容易引起不必要的錯誤。為此,如果單從這個工作量來考慮的話,那么數(shù)據(jù)庫管理員肯定喜歡采用這個約束,而不喜歡采用觸發(fā)器。
建議:
如果約束能夠?qū)崿F(xiàn)特定的功能,則數(shù)據(jù)庫最好能夠采用約束而不是觸發(fā)器。因為約束能夠提供比較高的執(zhí)行性能,而且數(shù)據(jù)庫管理員維護的工作量也會小得多。當然使用約束的前提是假設(shè)這些約束的功能能夠滿足應(yīng)用程序的功能需求。如果系統(tǒng)中現(xiàn)成的約束無法滿足企業(yè)用戶的需求,如功能無法滿足或者提供的錯誤信息不夠等情況,此時數(shù)據(jù)庫管理員就需要通過觸發(fā)器來完成。不過數(shù)據(jù)庫管理員在編寫觸發(fā)器的時候,仍然可以借鑒相關(guān)約束的實現(xiàn)方式。而不用從零開始,來重新設(shè)計觸發(fā)器。另外觸發(fā)器可以防止一些惡意或錯誤的記錄插入、刪除以及更新操作,并強制執(zhí)行比CHECK約束定義的限制更為復(fù)雜的其他限制。其還可以提供比CHECK約束更復(fù)雜一點的功能。如觸發(fā)器可以引用其他表中的列??梢娪|發(fā)器與約束各有各的特點。要從執(zhí)行性能、維護工作量、實現(xiàn)的功能、用戶友好性等多個方面出發(fā),選擇合適的處理方式。
電子發(fā)燒友App

















































評論