觸發器和事務之間的區別
我正在實施電影分級服務,所以我正在考慮使用觸發器或事務。
我正在考慮將電影資訊插入movie_list,並將該電影的流派插入movie_genre_list。
在這種情況下,我的想法是在插入電影資訊時編寫一個觸發器來插入流派。
但是,我不知道觸發器或事務是否適合這種情況。我該怎麼辦?
比較
TRIGGER
s 和TRANSACTION
s 就像比較蘋果和橘子!不,等等,不是,因為蘋果和橙子很相似——它們都是水果,都可以吃。它更像是粉筆和奶酪(英文表達)!
- 事務用於將操作分組到一個工作單元中,該工作單元要麼全部成功,要麼全部失敗!
INSERT
觸發器(通常)用於在數據庫中發生事件(通常是UPDATE
或DELETE
在特定表上)時執行(過程/業務邏輯)程式碼。
TRANSACTION
s。這些工作單元以獨立於其他事務的連貫和可靠的方式處理。
來自維基百科:
- 提供可靠的工作單元,允許從故障中正確恢復並保持數據庫一致,即使在系統故障的情況下,當執行停止(完全或部分)並且對數據庫的許多操作仍未完成且狀態不明確時。
- 在同時訪問數據庫的程序之間提供隔離。如果不提供這種隔離,則程序的結果可能是錯誤的。
請注意“隔離”一詞的使用——這是“酸”測試的標準之一。
ACID
在這種情況下,既對應於英語單詞的遊戲,也對應於數據庫事務的一組屬性,這些屬性被認為是非常可取的——它們是:A
tomicicty、C
onsistency、solationI
和D
urablility。典型的例子是銀行業。假設您想通過從您的目前賬戶轉賬來支付 100 歐元的信用卡賬單。因此,對於您和銀行來說,這一“交易”應該作為一個單一一致的工作單元發生,這一點很重要。否則,要麼您(錢離開您的活期賬戶,但沒有進入 CC 賬戶),要麼銀行(您的 CC 被記入貸方,但您的活期賬戶沒有被借記)是自掏腰包。
因此,在 SQL 中,您要做的是:
BEGIN TRANSACTION; UPDATE current_account ca SET ca.balance = ca.balance - 100 WHERE ca.cust_name = 'Haram'; UPDATE CC_account cc SET cc.balance = cc.balance + 100 WHERE cc.cust_name = 'Haram'; COMMIT; -- definitively perform the work.
如果任何步驟失敗(例如 current_account 中的餘額不足),事務的所有工作都將回滾 - 從而確保一致性。
最後一點——要是一切都這麼簡單就好了!:-) 有(至少)四個複雜因素:
1)不同的隔離級別。這超出了此答案的範圍-查看Wiki並使用您選擇的搜尋引擎-那裡有大量材料,並且
2)供應商的不同實現 - 您必須為此查看您自己的系統文件,並且
3)有嵌套
TRANSACTION
的 s 和SAVEPOINT
s 之類的東西-再次,這超出了此答案的範圍-檢查您的文件,並且
- 一些數據庫引擎支持事務性 DDL(數據定義語言)而一些(尤其是 MySQL)不支持。
TRIGGER
s。另一方面,數據庫是完全不同的動物!
TRIGGER
ATRIGGER
是一個動作(由開發人員編碼),它響應表上的事件而發生(同樣,這裡我不會討論複雜性 - 檢查 Wiki 和/或使用您的搜尋引擎)。在絕大多數情況下,所討論的事件是桌子上的一個INSERT
、一個UPDATE
或一個。DELETE
可以在這裡找到一個相當不錯的類比。數據庫上的一個動作被比作一排多米諾骨牌——你打倒第一個多米諾骨牌,其餘的在連鎖反應中倒下。這類似於 a
TRIGGER
會在其他表上引發進一步的事件等等!然而,最好不要把類比走得太遠——你想盡可能避免進行複雜的多錶鍊式更新——KISS。您可以看到循環引用(
TRIGGER
在 AUPDATE
s B 上又UPDATE
是 A…)可能是災難性的!從這裡:
您可以使用觸發器來執行以下操作,以及此列表中未找到的其他操作:
- 在數據庫中創建活動審計跟踪。例如,您可以通過將確證資訊更新到審計表來跟踪訂單表的更新。
- 實施業務規則。例如,您可以確定訂單何時超出客戶的信用額度並顯示相關消息。
- 派生在表或數據庫中不可用的附加數據。例如,當 items 表的數量列發生更新時,您可以計算對 total_price 列的相應調整。
(該連結還提到使用它們來強制執行 DRI(聲明性引用完整性)-我不同意-見答案的結尾)。
一個典型的(供應商語法在這裡變化很大 - 檢查您的系統的文件)
TRIGGER
骨架(範例取自此處)將是:CREATE TRIGGER `event_name` BEFORE/AFTER INSERT/UPDATE/DELETE ON `database`.`table` FOR EACH ROW BEGIN -- trigger body -- this code is applied to every -- inserted/updated/deleted row END;
身體可能看起來像這樣:
IF NEW.deleted THEN SET @changetype = 'DELETE'; ELSE SET @changetype = 'NEW'; END IF; INSERT INTO audit (blog_id, changetype) VALUES (NEW.id, @changetype);
這個觸發器是
INSERTING
一個記錄到一個audit
用id
被審計表(blog
在本例中呼叫)中呼叫的表中,並且還記錄了操作是 aDELETE
還是 anINSERT
。您還可以TIMESTAMP
在其中包含邏輯來跟踪操作發生的時間。此外,您可以添加 user_name 邏輯來審核誰在什麼時候INSERT
編輯/編輯DELETE
了什麼。可能性是無止境。概括。
因此,總而言之,a
TRANSACTION
將一組語句組合成一個邏輯單元,並TRIGGER
允許在數據庫本身中包含超出 SQL(複雜業務規則)範圍的邏輯。一開始我發現棘手的一件事是(如果未
TRANSACTION
指定),伺服器將代表您並COMMIT
在每個語句之後設置一個隱式事務。例如,這是 MySQL 伺服器的預設行為:
mysql> show variables like '%COMMIT%'; +-----------------------------------------+-------+ | Variable_name | Value | +-----------------------------------------+-------+ | autocommit | ON |
發出命令
mysql> SET autocommit = OFF; Query OK, 0 rows affected (0.00 sec)
現在,您可以試驗如果您連續發出多個命令並發出 a
COMMIT
以及當您沒有COMMIT
ting 退出時會發生什麼。更好的是,您可以嘗試隔離級別
mysql> show variables like '%ISOL%'; +-----------------------+-----------------+ | Variable_name | Value | +-----------------------+-----------------+ | transaction_isolation | REPEATABLE-READ | | tx_isolation | REPEATABLE-READ | +-----------------------+-----------------+
然後打開不同的終端會話,看看在不同條件下記錄可見性會發生什麼。
最後一句話:在我看來,您正處於數據庫之旅的開始階段。儘管我在這裡使用了 MySQL 作為範例,但我強烈(強烈)敦促您盡可能使用 PostgreSQL——它是一個比 MySQL優越得多的數據庫伺服器,並且更符合啟動標準!盡可能嘗試並使用命令行客戶端 - 一開始可能很繁瑣,但從長遠來看更強大且值得!
非常非常最後一句話(:-)) - 繼續閱讀並獲得一些好的文本並研究它們!ps 恭喜您在 dba.stackexchange 上提出第一個問題!
糟糕——差點忘了回答問題!
您可以(如果每部電影只有一種(主要)類型)執行以下操作:
- 創建一個
genre
表格並FOREIGN KEY
在您的movie
表格上有一個指向該genre_name
欄位(fiddle1)的表格,或者(如果您希望每部電影有多個類型 - 一個更有趣和現實的場景)這樣做: