李虎軍 金泉 邢旺 張政
摘要: 觸發(fā)器與完整性約束功能強大、使用靈活,該文著重對在不同情況下兩者使用時的優(yōu)缺點進行了探析,以期能對數據庫應用系統(tǒng)設計者與管理者進行數據管理、提高數據完整性控制提供有益幫助。
關鍵詞:完整性約束;觸發(fā)器;區(qū)別
中圖分類號:TP311 文獻標識碼:A 文章編號:1009-3044(2016)23-0010-03
如何保證數據庫應用系統(tǒng)中數據的正確性、一致性,是數據庫應用系統(tǒng)設計者與管理者必須要考慮的重要內容。通常,關系數據庫管理系統(tǒng)通過數據完整性規(guī)則(也稱數據約束),來避免數據庫中存在錯誤數據。除了數據完整性規(guī)則外,關系數據庫管理系統(tǒng)還可以通過觸發(fā)器來實現更復雜的數據約束和業(yè)務邏輯規(guī)則。盡管觸發(fā)器幾乎可以代替數據完整性來實現數據的正確性和一致性檢查,但觸發(fā)器和數據完整性各有優(yōu)缺點,在使用時數據庫應用系統(tǒng)設計者應充分考慮兩者的區(qū)別。
1 數據約束
數據約束通常分為實體完整性、值域完整性、參照完整性和用戶定義的完整性。
1.1 四類完整性約束
實體完整性規(guī)定在數據表中不允許有主鍵完全相同的兩條記錄存在以及主鍵不允許出現NULL值,也被稱為主鍵約束。每一張數據表都應建立主鍵約束。
參照完整性是指一個數據表A(參照表)中某列的數據必須已經在本表某個指定列中或同一數據庫中某個指定表B(即被參照表)中存在;當參照表A中有記錄參照被參照表B中數據時,禁止刪除被參照表B中相關數據,或修改被參照表B中相關數據時同時級聯修改參照表A中相應數據,也稱為外鍵約束(即FOREIGN KEY 約束)。通過在參照數據與被參照數據之間建立關聯關系,可以很好地維護表之間數據一致性。
值域完整性限制向表中輸入的值的范圍。例如,在表中屬性為tinyint的列只能輸入0到255范圍內的整數值。
用戶定義的完整性,就是針對某一具體關系數據庫的約束條件,它反映某一具體應用所涉及的數據必須滿足的語義要求。例如我國職工年齡在必須滿18周歲。用戶自定義的完整性可以通過多種方式得到體現。有非空約束、CHECK約束、唯一性(UNIQUE)約束、默認值約束等。
1.2 各種約束的特點
主鍵約束,確保了數據表中主碼不會出現重復,也就保證了表中不會出現重復的記錄。在定義主鍵約束時如果沒有指定 CLUSTERED 或 NONCLUSTERED,并且也沒有為 UNIQUE 約束指定聚集索引,則將對該主鍵約束默認使用 CLUSTERED,即意味著數據表將按主鍵進行物理排序并建立聚簇索引。每一張數據表只能有一個主鍵約束,主鍵約束可以在數據表的列級或表級上進行定義,但只能二選一。
外鍵約束,將兩個表中的數據關聯起來,當其中關聯數據進行插入、刪除、更新時按約束建立時設定的規(guī)則進行處理,保證關聯字段的數據一致性。被參照數據在被參照表中為主鍵??梢栽O定參照數據與被參照數據之間的級聯操作規(guī)則,具體規(guī)則可以分為拒絕操作、級聯操作、置NULL值、置默認值。
非空約束,指定某一列不允許存在空值或NULL(NULL代表值未知或未定義),即要求指定列必須包含數據。此約束可以避免指定列的值出現未知狀態(tài),要求相應列必須包含數據,有助于維護數據的完整性。
CHECK約束,對表輸入數據時按設定的條件進行檢查,只有符合條件的數據才允許進入數據表。可以在單列或多列上建立CHECK約束,一個表上可定義多個CHECK約束。CHECK約束同外鍵約束的相同之處在于,都是通過檢查數據的值合理性來實現數據完整性的維護。CHECK約束中不能包含子查詢,但指定條件必須是邏輯表達式,不可能很復雜。CHECK約束處理速度快,功能相對簡單。CHECK約束檢查的數據只能在同一張表上,不能引用其他表的數據。在執(zhí)行INSERT或UPDATE語句時CHECK約束將驗證數據。通過限制列可接受的值,CHECK 約束進一步實現值域完整性。
UNIQUE約束通常用于非主鍵的一列或多列上不輸入重復的值,要求各記錄該列值必須互不相同。UNIQUE約束允許該列上存在NULL值(但也只能有一個),而主鍵約束卻不允許出現NULL值??梢栽谝粋€表上定義多個UNIQUE約束,卻只能設置一個主鍵約束。當建立UNIQUE約束后,SQL Server會自動在該約束控制的列上創(chuàng)建UNIQUE索引以強制執(zhí)行數據的唯一性約束。當有重復數據輸入表中時,SQL SERVER會自動給出錯誤信息,并拒絕執(zhí)行命令。
默認值約束指在插入一條記錄時如果某字段(在設計表時指定默認值)沒有給出具體值,則系統(tǒng)自動賦予其默認值。
2 觸發(fā)器
通常,數據庫系統(tǒng)開發(fā)人員采用上述數據約束實現數據完整性。但面對復雜的檢查策略和操作時,SQL Server還提供了一種對數據進行檢查和操作的方法——觸發(fā)器。
2.1 觸發(fā)器概念
觸發(fā)器是用戶定義在數據表上的一種被事件驅動的由DBMS調用執(zhí)行的特殊存儲過程。在數據庫對象或在數據表上定義了相應的觸發(fā)器后,當用戶在數據表中修改、刪除、插入記錄或創(chuàng)建數據庫對象或執(zhí)行特定操作時將自動執(zhí)行相應的觸發(fā)器。
2.2 觸發(fā)器的特點
觸發(fā)器不能接收參數,也不能被用戶直接調用執(zhí)行。觸發(fā)器以及引起觸發(fā)器被執(zhí)行的相應操作被統(tǒng)一當做一次事務處理。如果該事務未能成功執(zhí)行,則DBMS會自動回滾到該事務執(zhí)行前的狀態(tài)。
根據觸發(fā)事件類別不同,觸發(fā)器可以分為DML(Data Manipulation Language)觸發(fā)器和DDL(Data Definition Language)觸發(fā)器。
DDL觸發(fā)器用于響應各種DDL事件。DDL事件主要對應于CREATE、DROP、ALTER語句和用戶登錄與退出等操作。DDL觸發(fā)器可被用于應用系統(tǒng)管理任務,還可用于審核與規(guī)范數據庫中對表結構、視圖結構上的操作;當數據庫或表結構發(fā)生變化時激發(fā)觸發(fā)器,可用觸發(fā)器記錄相應的修改過程,還可限制用戶對數據庫修改,禁止刪除指定表等操作,從而實現對數據庫系統(tǒng)的安全管理。
DML觸發(fā)器是在用戶使用DML語句對數據進行(刪除、更新、插入)操作時觸發(fā)執(zhí)行。DML事件針對表或視圖的INSERT、DELETE和UPDATE語句。在表或視圖上處理數據時可通過DML觸發(fā)器來進行相關業(yè)務規(guī)則檢查,進一步提高數據完整性。
根據在觸發(fā)語句前后執(zhí)行的不同,觸發(fā)器可分為INSTEAD OF觸發(fā)器和AFTER(FOR)觸發(fā)器兩種。
INSTEAD OF觸發(fā)器(可定義在數據表、視圖上)是在數據變動之前被調用執(zhí)行,并替代變動數據的操作語句,轉而執(zhí)行觸發(fā)器所定義的操作。INSTEAD OF觸發(fā)器可以替代用戶的相關操作語句,在用戶操作執(zhí)行前進行觸發(fā)器規(guī)定的相關操作。
AFTER觸發(fā)器(不能定義在視圖上)是在數據操作完成以后被調用執(zhí)行,因此可利用AFTER觸發(fā)器對變動后的數據進行相關業(yè)務規(guī)則檢查,可以接受或拒絕數據的改變。
不能在臨時表或系統(tǒng)表上創(chuàng)建觸發(fā)器。
2.3 觸發(fā)器代碼要簡短高效
觸發(fā)器是與激發(fā)它的SQL語句屬于同一事務的一部分,此SQL語句要等到觸發(fā)器執(zhí)行結束時才算真正完成。如果在觸發(fā)器的語句體中編寫了需要運行較長時間的代碼,也就意味著激發(fā)觸發(fā)器的每一段代碼都運行較長時間,如此將會使得應用系統(tǒng)執(zhí)行速度降低。在觸發(fā)器執(zhí)行中如果檢測到錯誤,則整個事務也自動回滾,所以觸發(fā)器的代碼執(zhí)行時間長將會使整個應用系統(tǒng)執(zhí)行效率降低。
3 合理選擇觸發(fā)器與完整性約束
數據約完整性束和觸發(fā)器的作用機制不同,在完成不同任務時各有優(yōu)勢與不足。
3.1 首選完整性約束
通常,能用完整性約束滿足應用系統(tǒng)業(yè)務邏輯需要的,就用完整性約束。
建立表的主鍵約束、外鍵約束、值域約束和用戶定義的完整性約束,對一個關系數據庫系統(tǒng)來說是基本要求,各種關系數據庫管理系統(tǒng)對上述的幾種完整性都有很好的支持。實體完整性是在數據庫管理系統(tǒng)的最低級別上通過索引進行強制,這些索引或是 PRIMARY KEY 和 UNIQUE 約束的一部分,或是在約束之外獨立創(chuàng)建的。參照完整性則應盡可能使用FOREIGN KEY 約束進行強制。如果域完整性可以滿足應用程序的需求,應通過 CHECK 約束進行強制。使用完整性約束進行應用系統(tǒng)業(yè)務邏輯檢查,DBMS處理速度快,效率高。
3.2 使用觸發(fā)器以滿足復雜的特殊需求
觸發(fā)器的主要優(yōu)點在于可以使用 SQL 代碼處理復雜邏輯。因此,觸發(fā)器可以支持完整性約束的所有功能;但它在功能上并不總是最好的方法。在完整性約束所支持的功能無法滿足應用程序的功能要求時,觸發(fā)器就極為有用。例如:除非在定義外鍵時建立了級聯引用操作,否則外鍵約束只能通過與另一列中的值完全匹配的值來驗證列值。
觸發(fā)器可通過數據庫中的相關表實現級聯更改;不過,通過級聯參照完整性約束可以更有效地執(zhí)行這些更改。觸發(fā)器可以禁止或回滾違反參照完整性的更改,從而取消所嘗試的數據修改;當更改外鍵且新值與主鍵不匹配時,此類觸發(fā)器就可能發(fā)生作用。
1)CHECK約束滿足不了特殊檢查需要
CHECK約束快且效率高,但不能完成所有檢查工作。觸發(fā)器可以定制檢查規(guī)則,并且這些定制的檢查規(guī)則可比CHECK約束所定義的規(guī)則更復雜、更強大。CHECK 約束只能作用于同一表中的數據,只能根據邏輯表達式或同一表中的另一列來驗證列值。如果應用程序要求根據另一個表中的列驗證列值,則需要使用觸發(fā)器。觸發(fā)器可以引用其他表中的列。例如,觸發(fā)器可以使用同一數據庫中另一個表中的 SELECT結果比較插入或更新的數據。
2)對被更新的中間數據進行處理
當我們對表中某字段的過去或現在的值不感興趣,只希望知道變化值是多少時,雖然沒有列或表提供這些變化信息,但可以利用觸發(fā)器中的inserted臨時表和deleted臨時表對相應記錄值進行相減計算就可得到是否發(fā)生變化信息。觸發(fā)器也可以評估數據修改前后的表狀態(tài),并根據其差異采取對策。一個表中的多個同類觸發(fā)器(INSERT、UPDATE 或 DELETE)允許采取多個不同的對策以響應同一個修改語句。
3)在數據庫設計時方便完整性更改
當表結構發(fā)生改變時,在原表上所建立的各種完整性約束都需要更改,有些需要先刪除后才能更改表結構;而建立表后,還需重新建立各種約束,較難保證沒有遺漏或差錯,這就給數據庫設計者帶來很大不便。觸發(fā)器不關心表結構的改變,其只關心是否能正確運行。因此對于使用觸發(fā)器建立的約束,在表結構發(fā)生更改時只需禁用觸發(fā)器即可,可為數據庫設計者提供很大的便利。在數據庫開發(fā)中可以先使用觸發(fā)器完成引用完整性,在開發(fā)完畢的時候將它改為DRI(聲明引用完整性)。
4)方便數據庫大批量數據導入
在數據庫開發(fā)完畢或維護時,當需要大批量導入數據時,此時可能希望關閉完整性方便導入數據;在這種情況下,如果使用觸發(fā)器實現數據完整性,就能更好地體現出觸發(fā)器的優(yōu)點來。通過關閉觸發(fā)器以減少導入時的過量開銷并實現數據的快速導入處理。
5)實現不同數據庫、不同服務器之間數據同步
參照完整性約束建立的數據一致性,不能跨數據庫實例。當需要在不同數據庫實例中建立數據一致性時(或數據備份、同步時),可以使用觸發(fā)器來實現。觸發(fā)器還可用于在不同服務器之間進行數據庫同步。對同構數據庫進行同步,可以將源數據庫更新了的內容生成相應臨時表,傳輸到目標數據庫,調用相應存儲過程進行同步。對于異構數據庫(不同DBMS),可采用XML文件作為數據交換的中介,在相應應用系統(tǒng)支持下進行同步。異構數據庫之間進行數據交換和同步的主要時機在于數據變化時的捕獲,通過觸發(fā)器可以較方便地得到實現。
6)對數據庫用戶進行特殊審計
當數據庫用戶進行一些特殊操作時,通過觸發(fā)器進行記錄,方便數據庫管理員進行安全檢查。例如,在密碼表中指定列上設定AFTER(FOR)觸發(fā)器,當相應的用戶名或密碼發(fā)生改動時,將操作者、操作對象、操作時間、前后變化了的數據等內容進行保存并通知數據庫管理員,為及時發(fā)現黑客、保障數據庫的安全提供幫助。還可以使用觸發(fā)器實現對數據表中特定數據的禁止修改或權限檢查。例如,很多注冊系統(tǒng)在用戶注冊后都不能更改用戶名,但該功能很多是由應用程序決定的, 如果通過打開數據庫表進行更改,就可以更改用戶名。為避免該情況發(fā)生,可以在觸發(fā)器中利用回滾或使語句出錯的方法來實現禁止更改用戶名功能,使對特定數據的更改操作無效。
7)使用觸發(fā)器傳遞自定義信息
完整性約束只能通過標準的系統(tǒng)錯誤信息傳遞錯誤信息。如果應用程序要求使用自定義信息或較為復雜的錯誤處理,則可以在觸發(fā)器中使用raiserror( )函數來完成。
3.3 注意觸發(fā)器與完整性約束的執(zhí)行順序
如果觸發(fā)器表上存在完整性約束,完整性約束則在 INSTEAD OF觸發(fā)器執(zhí)行后但在 AFTER觸發(fā)器執(zhí)行前檢查這些約束條件。如果完整性約束被破壞,則回滾INSTEAD OF觸發(fā)器操作并且不執(zhí)行 AFTER觸發(fā)器。
3.4 精簡設計觸發(fā)器
觸發(fā)器可以禁止或回滾違反業(yè)務邏輯規(guī)則的操作,但在觸發(fā)器中應盡量少用回滾?;貪L將會撤銷已完成的大量操作,將給系統(tǒng)運行帶來很大開銷,特別是影響大批量數據時,很可能造成數據庫系統(tǒng)服務性能的急劇下降。完整性約束是在實際操作發(fā)生之前執(zhí)行的,在所有工作完成前阻止失敗的事情發(fā)生。也就意味著約束的運行速度要快一些。觸發(fā)器中代碼應該短小精悍,如果觸發(fā)器中語句復雜或影響數據量大,使用觸發(fā)器所帶來的可能負面效率影響可能很大。因此建議盡可能使用完整性約束,少使用觸發(fā)器。
4 結束語
觸發(fā)器功能強大,靈活使用觸發(fā)器可以幫助數據庫系統(tǒng)設計者和維護者實現許多復雜的功能,能較好地提高信息系統(tǒng)的數據完整性。但要慎用觸發(fā)器,如果濫用會造成數據庫系統(tǒng)的維護困難,應合理選擇使用完整性約束和觸發(fā)器。
參考文獻:
[1] 王珊.數據庫系統(tǒng)概論[M].北京:高等教育出版社,2012.
[2] 鄒建.深入淺出SQL Server 2005開發(fā)、管理與應用實例[M]. 北京:人民郵電出版社,2008.
[3] 李霞. SQL Server約束在維護數據完整性中的運用[J].晉城職業(yè)技術學院學報,2012(5).