MySQL的事務處理及隔離級別

weixin_34232744發表於2018-06-20

要想知道什麼是資料庫事務,首先要知道為什麼資料庫需要事務管理。

要說事務的例子,最簡單的就是銀行轉賬,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,這是伺服器層實現的,和儲存引擎無關。

相關文章