[MySQL事務一文搞懂] 1、什麼是事務? 事務(Transaction),顧名思義就是要做的或所做的事情,資料庫事務指的則是作為單個邏輯工作單元執行的一系列操作(SQL語句)。這些操作要麼全部執行,要麼全部不執行。 2、為什麼需要事務 把一系列sql放入一個事務中有兩個目的: 為資料庫操作提供了 ...
[MySQL事務一文搞懂]
1、什麼是事務?
事務(Transaction),顧名思義就是要做的或所做的事情,資料庫事務指的則是作為單個邏輯工作單元執行的一系列操作(SQL語句)。這些操作要麼全部執行,要麼全部不執行。
2、為什麼需要事務
把一系列sql放入一個事務中有兩個目的:
-
為資料庫操作提供了一個從失敗中恢復到正常狀態的方法,同時提供了資料庫即使在異常狀態下仍能保持一致性的方法。
-
當多個應用程式在併發訪問資料庫時,可以在這些應用程式之間提供一個隔離方法,以防止彼此的操作互相干擾。
""" 當一個事務被提交給了DBMS(資料庫管理系統),則DBMS需要確保該事務中的所有操作都成功完成且其結果被永久保存在資料庫中,如果事務中有的操作沒有成功完成,則事務中的所有操作都需要被回滾,回到事務執行前的狀態(要麼全執行,要麼全都不執行);同時,該事務對資料庫或者其他事務的執行無影響,所有的事務都好像在獨立的運行。 但在現實情況下,失敗的風險很高。在一個資料庫事務的執行過程中,有可能會遇上事務操作失敗、資料庫系統/操作系統失敗,甚至是存儲介質失敗等情況。這便需要DBMS對一個執行失敗的事務執行恢復操作,將其資料庫狀態恢復到一致狀態(數據的一致性得到保證的狀態)。為了實現將資料庫狀態恢復到一致狀態的功能,DBMS通常需要維護事務日誌以追蹤事務中所有影響資料庫數據的操作。 """
3、事務的四大特性(ACID)
ACID 即Atomicity、Consistency、Isolation、Durability的縮寫
1、原子性(Atomicity)
一個事務的執行是整體性的,不可分割,包含在其中的對資料庫的操作要麼全部被執行,要麼都不執行。
2、一致性(Consistency)
事務應確保資料庫的狀態從一個一致狀態轉變為另一個一致狀態。例如轉賬行為中:一個人減了50元,另 外一個人就應該加上這50元,而不能 是40元。其他一致狀態的含義是資料庫中的數據應滿足完整性約束, 例如欄位約束不能為負數,事務執行完畢後的該欄位也同樣不是負數
3、隔離性(Isolation)
多個事務併發執行時,一個事務的執行不應影響其他事務的執行, 且多個事務不能看到對方的中間狀態(提交或者回滾之前的狀態)
4、持久性(Durability)
一個事務的提交,對資料庫的修改是永久保存在資料庫中的,不受外部因素或其他操作影響。
4、事務的隔離級別
註意: 下方表格即代表 每個隔離級別是否存在併發事務所導致的問題!
隔離級別 | 臟讀 | 不可重覆讀 | 幻讀 |
---|---|---|---|
Read uncommitted 讀未提交 | √ | √ | √ |
Read committed 讀已提交 | × | √ | √ |
Repeatable Read (MySQL預設隔離級別) 可重覆讀 | × | × | √ |
Serializable 串列化 | × | × | × |
5、併發事務導致的問題!
註意:下列問題其實就是由於併發事務可能會出現的問題(可用提高資料庫隔離級別解決 下麵會詳解)
-
臟讀(dirty read)
""" 臟讀其實就是 事務A 讀取到了 事務B 未提交的數據! 比如: 事務A 查詢賬戶金額為200 在此期間 事務B 將當前賬戶存入100 但是並未提交事務(事務只有再提交後才生效) 接下來 事務A 又查詢了當前賬戶金額 發現為300! 事務B 並未提交數據 而 事務A 則讀取到事務B未提交後的數據! 解決: 將資料庫隔離級別修改為: Read committed """
-
不可重覆讀(non repeatable read)
""" 不可重覆讀其實就是 事務A 執行相同的Sql卻讀取到了不同的數據! (和臟讀不同的是 它讀取到的是已經提交過的事務數據) 比如: 事務A 查詢賬戶金額為 200 事務B 修改金額為300 並且提交事務 然後 事務A 又查詢了賬戶金額發現為 300 這樣就導致了 事務A 再同一次事務中執行同樣的Sql而獲取到不同的值! 解決: 將資料庫隔離級別修改為: Repeatable Read """
-
幻讀(phantom read)
""" 幻讀其實就是事務A再查詢某條數據發現並不存在!但是再插入數據的時候卻發生ERROR說當前數據已經存在 (其實這是再不可重覆讀解決後發生的下一個問題) 比如: 事務A 查詢 ID=3 的數據沒有! 此時 事務B 啟動 執行插入了 id=3的一條數據 然後 事務A 發現ID為3的數據 並沒有 也插入了一條 id=3的數據後報錯說 已經存在! 這是因為 我們的數據隔離級別已經是可重覆的 所以事務A 每次查詢到的都是最初未改變的狀態! 解決: 將資料庫隔離級別修改為: Serializable """