溫立輝
(河源職業(yè)技術(shù)學(xué)院 電子與信息工程學(xué)院,廣東 河源 517000)
觸發(fā)器是關(guān)系數(shù)據(jù)庫進(jìn)行數(shù)據(jù)維護(hù)的一種重要機制[1],其能實現(xiàn)比關(guān)系數(shù)據(jù)自身攜帶CHECK函數(shù)更加強大的功能,目前主流的關(guān)系型數(shù)據(jù)庫均支持這一重要的數(shù)據(jù)維護(hù)機制,觸發(fā)器的應(yīng)用存在于各種各樣的業(yè)務(wù)場景中。
觸發(fā)器作為一種數(shù)據(jù)維護(hù)機制,既不同于關(guān)系數(shù)據(jù)庫自身所擁有的函數(shù),也不同于關(guān)系數(shù)據(jù)庫中的存儲過程,而是一種基于事件與時間作為監(jiān)測點的功能代碼塊。文獻(xiàn)[2-6]描述了觸發(fā)器的底層原理及相關(guān)的實現(xiàn)機制,闡述了觸發(fā)器的功能作用及應(yīng)用場景。從廣泛意義上來說,觸發(fā)器也是屬于關(guān)系數(shù)據(jù)庫中的功能函數(shù),用戶可以自行定義相關(guān)的觸發(fā)器函數(shù),但此類型的自定義函數(shù)不能帶有任何的參數(shù),這是與一般函數(shù)的重要區(qū)別。同樣,從廣義上來說,觸發(fā)器也是關(guān)系數(shù)據(jù)庫中一種特殊的存儲過程,但與一般存儲過程有一個非常重要的區(qū)別就是,存儲過程需要顯式的被調(diào)用,而觸發(fā)器則是無須被系統(tǒng)或用戶顯式調(diào)用,只要當(dāng)相關(guān)事件發(fā)生時就能自動觸發(fā)執(zhí)行相關(guān)觸發(fā)器的功能代碼語句,從這個意義上來說觸發(fā)器是自動被執(zhí)行,不需要手動調(diào)用。
觸發(fā)器存在于關(guān)系數(shù)據(jù)庫服務(wù)器端[7],其功能除了數(shù)據(jù)完整性約束之外,還能實現(xiàn)數(shù)據(jù)審計,數(shù)據(jù)表級聯(lián)操作等功能。所謂的數(shù)據(jù)審計是指跟蹤關(guān)系數(shù)據(jù)庫業(yè)務(wù)表中數(shù)據(jù)的變化過程,以審核數(shù)據(jù)變化過程是否合法,是否存在不規(guī)范的操作,以保證業(yè)務(wù)數(shù)據(jù)的正當(dāng)、準(zhǔn)確、合理。數(shù)據(jù)表級聯(lián)操作是指業(yè)務(wù)數(shù)據(jù)表之間是一個一個統(tǒng)一的有機整體,而不是獨立、分散的個體,當(dāng)某張數(shù)據(jù)表變化時會引起與此表相關(guān)聯(lián)的相關(guān)數(shù)據(jù)表的同時變化。如,在一個用戶模塊中,當(dāng)從用戶表刪除一條用戶記錄時,也必需從其他的業(yè)務(wù)表中刪除此用戶訂閱的相關(guān)業(yè)務(wù)記錄,否則業(yè)務(wù)系統(tǒng)會出異常。
觸發(fā)器是作用于數(shù)據(jù)表上的一種操作監(jiān)測機制[1],在關(guān)系數(shù)據(jù)庫中存在多種類型,一般來說常見的是關(guān)系數(shù)據(jù)庫管理語言中(Data Manipulation Language,DML)中的插入、刪除、更新3種操作類型的觸發(fā)器,在對數(shù)據(jù)表進(jìn)行insert,delete,update3種操作會觸發(fā)對應(yīng)類型的觸發(fā)器。
觸發(fā)器的觸發(fā)時間點有之前(before)與之后(after)兩種,當(dāng)定義了觸發(fā)時間點為before時,則會在對數(shù)據(jù)表的操作發(fā)生之前先行觸發(fā)數(shù)據(jù)表上的觸發(fā)器,觸發(fā)器功能代碼執(zhí)行完畢后才能執(zhí)行增、刪、改的數(shù)據(jù)操作;after類型則恰好相反,在對數(shù)據(jù)表執(zhí)行完增、刪、改操作后才觸發(fā)數(shù)據(jù)表上的觸發(fā)器功能代碼。
不言而喻觸發(fā)器是一種強大的數(shù)據(jù)維護(hù)機制,在關(guān)系數(shù)據(jù)庫的底層其采用的是逐行檢查以及臨時表的方式實現(xiàn)其強大的數(shù)據(jù)維護(hù)功能。
逐行檢查觸發(fā)器的一個基本原則,當(dāng)一個數(shù)據(jù)表的某個字段做了某項自定義約束時,如會員表的年齡字段為必須大于18,當(dāng)某個業(yè)務(wù)操作要修改會員表中某一條記錄的年齡字段值時,則觸發(fā)器會檢查整個會員表中每一行記錄的年齡字段的值是否有小于18的情況,如有回滾此次操作。這一原則當(dāng)然能保證數(shù)據(jù)約束的完整功能,但同時也會引入其他的問題,如性能問題;在業(yè)務(wù)表中數(shù)據(jù)量比較大的情況下,逐行檢查嚴(yán)重影響數(shù)據(jù)庫管理系統(tǒng)性能。
使用臨時表是觸發(fā)器另一重要原則,當(dāng)對業(yè)務(wù)表進(jìn)行增、刪、改的操作進(jìn)而觸發(fā)相應(yīng)的觸發(fā)器時,觸發(fā)器會對操作將觸動的業(yè)務(wù)數(shù)據(jù)在臨時表中進(jìn)行備份,以供后面所需的回滾、恢復(fù)操作。觸發(fā)器中存在有插入臨時表(insert表)與刪除臨時表(delete表)兩種。
當(dāng)外部要往數(shù)據(jù)表中插入新的數(shù)據(jù)時,觸發(fā)器首先會往insert臨時表中插入新數(shù)據(jù),然后再往目標(biāo)數(shù)據(jù)表插入相關(guān)數(shù)據(jù),新數(shù)據(jù)進(jìn)入目標(biāo)數(shù)據(jù)表后再檢查新插入的數(shù)據(jù)是否合法,如合法則直接刪除insert臨時表中的數(shù)據(jù),如不合法則按insert臨時表保存的數(shù)據(jù)去刪除目標(biāo)數(shù)據(jù)表中新進(jìn)入的數(shù)據(jù)。
當(dāng)外部要從業(yè)務(wù)數(shù)據(jù)表刪除數(shù)據(jù)時,觸發(fā)器則會先把要刪除的舊數(shù)據(jù)插入delete臨時表進(jìn)行數(shù)據(jù)備份,然后再從目標(biāo)數(shù)據(jù)表刪除相關(guān)數(shù)據(jù),最后檢查刪除操作是否合法,如果合法則直接從delete臨時表中刪除之前備份的數(shù)據(jù),如不合法則用備份好的數(shù)據(jù)恢復(fù)到原目標(biāo)數(shù)據(jù)表中。
當(dāng)外部要從業(yè)務(wù)數(shù)據(jù)表修改某條業(yè)務(wù)數(shù)據(jù)時,觸發(fā)器則會往兩張臨時表中備份數(shù)據(jù)。首先,把目標(biāo)數(shù)據(jù)表中要被修改的舊數(shù)據(jù)備份到delete臨時表;然后,再把修改后的數(shù)據(jù)同時寫入目標(biāo)數(shù)據(jù)表與insert臨時表;最后,檢查操作是否合法,如果合法則刪除兩張臨時表中的數(shù)據(jù),反之如果不合法,則按insert臨時表的數(shù)據(jù)去刪除目標(biāo)數(shù)據(jù)表數(shù)據(jù),并把delete臨時表備份數(shù)據(jù)恢復(fù)到目標(biāo)數(shù)據(jù)表中。
從逐行檢查與使用臨時表兩個原則中可知,觸發(fā)器在一定程度會影響到數(shù)據(jù)庫性能,因而在使用觸發(fā)器前一定要嚴(yán)格謹(jǐn)慎,如果有其他更好的解決方案則盡可能不使用觸發(fā)器。
凡事物都是具有兩面性的,雖然觸發(fā)器的使用會在一定程度影響系統(tǒng)性能,但是觸發(fā)器還是非常廣泛地應(yīng)用于很多的業(yè)務(wù)場景中,只要使用得當(dāng),考慮周全,觸發(fā)器有非常廣闊的天地,如以下兩個場景中,就可以考慮使用觸發(fā)器。
在一個電子商城平臺中需開發(fā)一個秒殺搶購功能,按常規(guī)的思維,Web應(yīng)用服務(wù)先從數(shù)據(jù)表中讀取庫存數(shù)據(jù),再通過判斷其是否大于0進(jìn)而結(jié)論是否成功秒殺到。在秒殺過程中當(dāng)庫存數(shù)剩余為1時,因為平臺上有多個Web節(jié)點,所以可能多個線程同時讀取庫存數(shù)為1并多個線程同時下結(jié)論成功搶到,但1件商品是不可能同時被多個人搶到的,因而常規(guī)思維走不通。
此時就要從后臺數(shù)據(jù)庫入手,可考慮在數(shù)據(jù)庫的商品表的庫存數(shù)量字段加個約束讓其不能小于0,一般的數(shù)據(jù)庫中可考慮使用CHECK函數(shù)進(jìn)行約束就可以了,但MySQL中不支持CHECK函數(shù)功能,因而無法使用這一方式,必須使用觸發(fā)器來對這個庫存數(shù)量字段加一個不能小于0的約束,當(dāng)秒殺開始時對庫存數(shù)量的修改使用如下的累減原子操作SQL語句“UPDATE 商品表 SET 庫存數(shù)量=庫存數(shù)量-1”即可解決上面的問題。
交通違章管理系統(tǒng)記錄著所有車輛交通違章信息,只有內(nèi)部人員能操作系統(tǒng)中的相關(guān)數(shù)據(jù),但如果有工作人員違規(guī)私下修改或刪除系統(tǒng)里面數(shù)據(jù),那就是一個很大的漏洞。
針對這一問題就可以考慮使用觸發(fā)器對相關(guān)的業(yè)務(wù)數(shù)據(jù)表作數(shù)據(jù)的跟蹤審計,記錄下數(shù)據(jù)變化全過程,比如,哪個用戶在什么時間基于什么理由修改了什么數(shù)據(jù),這樣業(yè)務(wù)系統(tǒng)中整個數(shù)據(jù)變化過程就能正常的追蹤,堵塞了管理上的重大漏洞。
觸發(fā)器作為一種獨立的機制,其強大功能與優(yōu)勢是顯而易見的,缺少觸發(fā)器機制的關(guān)系數(shù)據(jù)庫是不完整的。觸發(fā)器雖然如此強大與重要,但決不能亂用,更不能濫用,如果使用不當(dāng)極容易使數(shù)據(jù)庫系統(tǒng)變得性能、效率低下。使用觸發(fā)器需堅持一個原則,那就是:必需、必要、數(shù)據(jù)量小。