MySql中的事務,隔離機制以及涉及到的鎖總結
純手打,希望可以幫助大家, 轉載的話附上鍊接就可以啦. 希望大家多提意見,逐步完善
- MySql事務
事務就是一組SQL要麼全部成功執行,要麼全都不執行,哪怕其中任何一個SQL出現操作異常執行過的SQL也會進行回滾
事務的性質(A C I D)
- Atomic **原子性:**整個事務是一個原子操作,要麼全部成功,要麼會回滾到初始狀態,just like 整個事務中的sql從未執行過一樣
- Consistency **一致性:**數據庫經過事務以後,整個數據庫狀態是完美從一個狀態到另一個狀態,是完全符合規則的.例如 A向B轉了一百塊,最後的狀態是A的賬戶少了100,B的賬號多了100. 這就是一致性
- Isolation **隔離性:**數據庫允許並行多個事務執行數據的更新,隔離性可以防止多個事務併發交叉執行而導致的數據不一致問題. 事務隔離分爲多個級別,包括 未提交(Read uncommitted),讀提交(read committed),可重複讀(repeatable read)和串行化(Serializable)
- Durability **持久性:**一個事務執行完畢,對數據的修改時永久的,及時系統故障也不會丟失
-
事務的隔離級別
離級別 髒讀可能性 不可重複讀可能性 幻讀可能性 加鎖讀 ead Uncommitted Yes Yes Yes N0 ead Committed No Yes Yes No epeatable Read No No Yes No erializable No No No Yes 隔離級別是針對在多個事務在併發情況下出現的數據問題例如:髒讀,不可重複讀,幻讀採取的不同隔離標準.我們按照數據安全級別由低到高來講下上邊的四個隔離級別:
- 未提交讀(Read uncommitted):最低的隔離級別,啥也保證不了,一般不會使用
- 已提交讀(Read committed):解決了髒讀的問題,不會讀取到其他事物事物未提交所做的新增和更新
- 可重複讀(Repeatable read):解決了髒讀,和不可重複讀,但是會出現幻讀. Mysql的InnoDB引擎默認就是該隔離級別
- 串行化(Serializable):最高級別,但是併發處理能力最低,魚和熊掌不能兼得
這是四個隔離級別,那麼我們講一下上邊出現的數據問題,究竟什麼是髒讀?不可重複讀?幻讀?
- 髒讀:事務A會讀取到事務B還沒有提交事務之前做的數據更改,事務A此時讀到的數據還沒有真正持久化到數據庫,萬一事務B回滾了,那麼事務A讀到的數據就是’髒’的
- 不可重複讀: 不可重複讀面向的重點是update/delete情況下出現的,在一個事務A中假設查詢了兩次賬戶餘額,由於別的事務更新操作,兩次查詢到的賬戶餘額是不一樣的,此時就說是不可重複讀
- 幻讀: 幻讀主要針對別的數據進行的Insert操作,比如在一個事務A中要插入一條ID爲10的數據,並且查詢的時候沒有ID爲10的數據存在,但是插入的時候報錯,說ID重複,這就是典型的幻讀場景
針對以上可能會因爲併發事務導致的問題主要解決方式有如下兩種
- 在讀取數據之前,對其加鎖,阻止其他事務對其進行修改,那麼以上問題都可解決
- 另一種是不用加任何鎖,通過一定機制生成一個數據請求時間點的一致性數據快照(Snapshot),並用這個快照來提供一定級別(語句級或事務級)的一致性讀取。從用戶的角度來看,好像是數據庫可以提供同一數據的多個版本,因此,這種技術叫做數據多版本併發控制(MultiVersion Concurrency Control,簡稱MVCC或MCC),也經常稱爲多版本數據庫。
-
MySQL中的鎖
MyISAM
引擎的鎖只支持表鎖,還有支持併發條件下的尾部插入,MyISAM也不支持事務,在此不做爲重點講解.InnoDB
引擎支持事務,並且不僅支持表鎖,還支持行鎖來提高併發下的吞吐量-
表鎖:在操作更新或者讀取的時候,將整個表鎖住,不允許任何對該表的查找和修改,保證了表數據的正確性,但是導致併發效率很低,很多會話會處於等待狀態浪費資源,造成很低的吞吐量
-
行鎖:
InnoDB
實現了兩種行鎖-
共享鎖(S):允許多個事務獲取該共享鎖
Share Lock
,但是大家都不能對該行數據進行修改,要想修改該行數據(要獲取該行的排它鎖,也就是寫鎖 必須等待所以共享鎖事務釋放完畢纔可以) -
排它鎖(X):一個事務一旦獲取數據A的排它鎖,其他任何事物都無法獲取鎖(但是可以進行查詢,只是不能獲取共享鎖,排它鎖而已),只能進行等待,排它鎖即可讀數據又可以寫數據
-
意向鎖:意向鎖是表級鎖,其設計目的是爲了揭示事務中下一行將要被請求鎖的類型,InnoDB中的兩個表鎖
意向共享鎖(IS):表示事務準備給數據加共享鎖,也就是加共享鎖之前首先要獲得該表的IS鎖
意向排它鎖(IX):表示事務準備給數據行加排它鎖,說明一個事務在對一行數據加排它鎖之前首先必須獲得該數據的IX鎖
意向鎖是InnoDB自動加的,不需要用戶干預
-
鎖的總結:
對於insert、update、delete,InnoDB會自動給涉及的數據加排他鎖(X);對於一般的Select語句,InnoDB不會加任何鎖,事務可以通過以下語句給顯示加共享鎖或排他鎖。
共享鎖:
SELECT ... LOCK IN SHARE MODE;
排他鎖:
SELECT ... FOR UPDATE;
-
-
間隙鎖(Next-Key鎖)
間隙鎖舉例: 當前user表中有ID爲:1-101條數據
當執行
select * from user where ID>100 for update
這個範圍查找並且獲取排它鎖加鎖情況: 不僅僅對滿足條件且真實存在的ID=101數據加鎖, 對不存在數據庫中的飯爲 ID>101 這個很大的
間隙
加鎖, 也就是其他嘗試插入的SQL會阻塞等待 -
深入瞭解行鎖:
- 在InnoDB當中,行鎖是鎖在對應的索引上,此處應該注意只有通過索引查找的數據纔會使用行鎖,否則將使用表鎖,需要注意這點,非常影響效率
- 雖然不是相同的行,如果使用的是相同的索引,則獲取鎖的兩行的時候會衝突,因爲索引相同,則鎖兩個行鎖資源一樣.
- 即便在條件中使用了索引字段,但是否使用索引來檢索數據是由MySQL通過判斷不同執行計劃的代價來決定的,如果MySQL認爲全表掃描效率更高,比如對一些很小的表,它就不會使用索引,這種情況下InnoDB將使用表鎖,而不是行鎖。因此,在分析鎖衝突時,別忘了檢查SQL的執行計劃,以確認是否真正使用了索引。