要想知道什麼是資料庫事務,首先要知道為什麼資料庫需要事務管理。
要說事務的例子,最簡單的就是銀行轉賬,A向B轉賬100,首先要將A記錄中的金額減去100,再將B記錄中的金額加上100,這才算是完成一次轉賬。可是,程式執行中可能出現各種不可控因素,如果在A減去100之後,銀行停電或者地震之類的,各種原因導致程式停止,並沒有執行對B賬戶的操作,A減去了100,可是B沒有加上。這時候就需要事務管理。
一、事務的四個特性
1、一般來說,事務是必須滿足4個條件(ACID)
原子性(Autmic):事務在執行性,就是說不允許事務部分得執行,一個事務是一個不可分割的工作單位。即使因為故障而使事務不能完成,rollback後也要回退到對資料庫進行操作前的狀態。
一致性(Consistency):事務必須是使資料庫從一個一致性狀態變到另一個一致性狀態。一致性與原子性是密切相關的。比如A,B賬戶相互轉賬之後,總金額不變。
隔離性(Isolation):一個事務的執行不能被其他事務干擾,當多個事務併發執行時,各個事務不會互相影響。
永續性(Durability):持續性也稱永久性(permanence),指一個事務一旦提交,它對資料庫中資料的改變就應該是永久性的。
2、事務的四個特性(ACID)是由關聯式資料庫管理系統(RDBMS,資料庫系統)來實現的。資料庫管理系統採用日誌來保證事務的原子性、一致性和永續性。日誌記錄了事務對資料庫所做的更新,如果某個事務在執行過程中發生錯誤,就可以根據日誌,撤銷事務對資料庫已做的更新,使資料庫退回到執行事務前的初始狀態。
資料庫管理系統採用鎖機制來實現事務的隔離性。當多個事務同時更新資料庫中相同的資料時,只允許持有鎖的事務能更新該資料,其他事務必須等待,直到前一個事務釋放了鎖,其他事務才有機會更新該資料。
二、關於髒讀,不可重複讀、幻讀
1、髒讀(DirtyReads):所謂髒讀就是對髒資料(Drity Data)的讀取,而髒資料所指的就是未提交的資料。一個事務正在對一條記錄做修改,在這個事務完成並提交之前,這條資料是處於待定狀態的(可能提交也可能回滾),這時,第二個事務來讀取這條沒有提交的資料, 並據此做進一步的處理,就會產生未提交的資料依賴關係。
2、不可重複讀(Non-RepeatableReads):一個事務先後讀取同一條記錄,期間另一個事務修改了資料,並且已經commit,所以兩次讀取的資料不同,稱之為不可重複讀。 3、幻讀(PhantomReads):一個事務先後讀取同一個表,期間其他事務插入了新的資料,並且已經commit,這種現象就稱為幻讀。 它和不可重複讀的區別:不可重複讀的重點是修改,幻讀重點是新增和修改。
三、隔離級別
既然知道了事務會有髒讀,不可重複讀和幻讀的現象,那就需要去控制他們,所以有了隔離級別。 一般隔離級別有四級:
READ UNCOMMITTED:幻讀,不可重複讀和髒讀均允許
複製程式碼
如果資料庫的隔離級別為REAE UNCOMMITTED, 則其他執行緒可以看到未提交的資料, 因此就出現髒讀。
READ COMMITTED:允許幻讀和不可重複讀,但不允許髒讀
複製程式碼
如果資料庫隔離級別設為READ_COMMITTED,即沒提交的資料別人是看不見的,就避免了髒讀.但是,正在讀取的資料只獲得了讀取鎖,讀完之後就解鎖,不管當前事務有沒有結束,這樣就容許其他事務修改本事務正在讀取的資料。導致不可重複讀。
REPEATABLE READ:允許幻讀,但不允許不可重複讀和髒讀
複製程式碼
REPEATABLE READ因為對正在操作的資料加鎖,並且只有等到事務結束才放開鎖, 則可以避免不可重複讀。
SERIALIZABLE:幻讀,不可重複讀和髒讀都不允許
複製程式碼
SERIALIZABLE因為獲得範圍鎖,且事務是一個接著一個序列執行,則保證了不會發生幻讀。
隔離級別 | 髒讀可能性 | 不可重複讀可能性 | 幻讀可能性 | 加鎖讀 |
---|---|---|---|---|
READ UNCOMMITTED | YES | YES | YES | NO |
READ COMMITTED | NO | YES | YES | NO |
REPEATABLE READ | NO | NO | YES | NO |
SERIALIZABLE | NO | NO | NO | YES |
所以說,READ UNCOMMITTED級別最低,SERIALIZABLE級別最高。 級別越高肯定對於維護事務的四個特性就越好,但是它犧牲的是資料庫的效率,因為SERIALIZABLE的實現是類似於java中的執行緒鎖。
ORACLE預設的是 READ COMMITTED,預設事務管理是開啟的,使用DML語言對資料操作需要提交(commit),出錯後可以回滾(rollback)。MYSQL預設的是 REPEATABLE READ,事務預設自動提交,若想開啟事務,使用set autocommit 命令。
Mysql提供了兩種事務型的儲存引擎:InnoDB和NDB Cluster.通過執行SET TRANSACTION ISOLATION LEVEL 設定隔離級別。新的隔離界別會在下一個事務開始時生效,也可以在配置檔案中設定整個資料庫的隔離級別。
mysql>SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
複製程式碼
四、隱式和顯式鎖定
1.InnoDB採用的是兩階段鎖定協議。事務執行過程中,隨時都可以鎖定,在執行COMMIT或者ROLLBACK的時候才會釋放。InnoDB還會根據隔離級別在需要的時候自動加鎖。
2.InnoDB也支援通過特定的語句進行顯示鎖定。
SELECT XXX LOCK IN SHARE MODE
SELECT XXX FOR UPDATE
複製程式碼
MYSQL也支援LOCK TABLES 和UNLOCK TABLES,這是伺服器層實現的,和儲存引擎無關。