Trigger

觸發器和事務之間的區別

  • May 27, 2018

我正在實施電影分級服務,所以我正在考慮使用觸發器或事務。

我正在考慮將電影資訊插入movie_list,並將該電影的流派插入movie_genre_list。

在這種情況下,我的想法是在插入電影資訊時編寫一個觸發器來插入流派。

但是,我不知道觸發器或事務是否適合這種情況。我該怎麼辦?

比較TRIGGERs 和TRANSACTIONs 就像比較蘋果和橘子!不,等等,不是,因為蘋果和橙子很相似——它們都是水果,都可以吃。它更像是粉筆和奶酪(英文表達)!

  • 事務用於將操作分組到一個工作單元中,該工作單元要麼全部成功,要麼全部失敗!
  • INSERT觸發器(通常)用於在數據庫中發生事件(通常是UPDATEDELETE在特定表上)時執行(過程/業務邏輯)程式碼。

TRANSACTIONs。

這些工作單元以獨立於其他事務的連貫和可靠的方式處理。

來自維基百科:

  1. 提供可靠的工作單元,允許從故障中正確恢復並保持數據庫一致,即使在系統故障的情況下,當執行停止(完全或部分)並且對數據庫的許多操作仍未完成且狀態不明確時。
  2. 在同時訪問數據庫的程序之間提供隔離。如果不提供這種隔離,則程序的結果可能是錯誤的。

請注意“隔離”一詞的使用——這是“”測試的標準之一。ACID在這種情況下,既對應於英語單詞的遊戲,也對應於數據庫事務的一組屬性,這些屬性被認為是非常可取的——它們是:Atomicicty、Consistency、solationIDurablility。

典型的例子是銀行業。假設您想通過從您的目前賬戶轉賬來支付 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 和SAVEPOINTs 之類的東西-再次,這超出了此答案的範圍-檢查您的文件,並且

  1. 一些數據庫引擎支持事務性 DDL(數據定義語言)而一些(尤其是 MySQL)不支持。

TRIGGERs。

另一方面,數據庫是完全不同的動物TRIGGERATRIGGER是一個動作(由開發人員編碼),它響應表上的事件而發生(同樣,這裡我不會討論複雜性 - 檢查 Wiki 和/或使用您的搜尋引擎)。在絕大多數情況下,所討論的事件是桌子上的一個INSERT、一個UPDATE或一個。DELETE

可以在這裡找到一個相當不錯的類比。數據庫上的一個動作被比作一排多米諾骨牌——你打倒第一個多米諾骨牌,其餘的在連鎖反應中倒下。這類似於 aTRIGGER會在其他表上引發進一步的事件等等!

然而,最好不要把類比走得太遠——你想盡可能避免進行複雜的多錶鍊式更新——KISS。您可以看到循環引用(TRIGGER在 A UPDATEs 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一個記錄到一個auditid被審計表(blog在本例中呼叫)中呼叫的表中,並且還記錄了操作是 aDELETE還是 an INSERT。您還可以TIMESTAMP在其中包含邏輯來跟踪操作發生的時間。此外,您可以添加 user_name 邏輯來審核誰在什麼時候INSERT編輯/編輯DELETE了什麼。可能性是無止境。

概括。

因此,總而言之,aTRANSACTION將一組語句組合成一個邏輯單元,並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)

現在,您可以試驗如果您連續發出多個命令並發出 aCOMMIT以及當您沒有COMMITting 退出時會發生什麼。

更好的是,您可以嘗試隔離級別

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)的表格,

或者(如果您希望每部電影有多個類型 - 一個更有趣和現實的場景)這樣做:

  • 如上所述創建一個genreand表,但在兩者之間也有一個連接表(或關聯實體)(fiddle2)。movie``movie_genre

引用自:https://dba.stackexchange.com/questions/207916