必须懂的 MySQL 的事务与隔离级别
??點擊上方?好好學java?,選擇?星標?公眾號
重磅資訊、干貨,第一時間送達 今日推薦:微信支付的軟件架構,牛逼!個人原創+1博客:點擊前往,查看更多 出處:哈基石 鏈接:https://segmentfault.com/a/1190000022610363事務的特性 ACID
- 原子性(atomicity) 一個事務為不可分割的最小工作單元,要么全部提交成功,要么全部回滾,不可能只執行一部分,這就是事務的原子性 
- 一致性(consistency) 數據庫從一個一致性狀態切換到另一個一致性狀態 
- 隔離性(isolation) 一個事務在提交之前,對其他事務是不可見的。 
- 永久性(durability) 一旦事務提交,那么所做的修改將會永久存儲在數據庫中 
事務的隔離級別
READ UNCOMMITED(未提交讀)臟讀
事務中的修改即使沒有提交,對其他事務都是可見的。會出現臟讀(Dirty Read)的情況。
READ COMMITTED (提交讀)不可重復讀
一個事務從開始直到提交之前,所做的任何修改對其他事務都是不可見的。也叫做不可重復讀(nonrepeatable read),因為兩次同樣的查詢,可能會存在不同的結果舉例說明:比如事務A正在讀數據庫內容,而事務 B 修改了數據后提交了。此時事務A又讀了一次數據庫內容,這時出現兩個內容不同的結果,稱為不可重復讀。
REPEATABLE READ(可重復讀)幻讀 MySQL 默認的事務隔離級別
當某個事務在讀取某個范圍內的記錄時,另外一個事務在這個范圍內插入了新的記錄,當之前的事務再次讀取這個范圍內的數據時,會產生幻行(Phantom Row)稱為幻讀舉例說明:比如事務 A 正在讀數據庫內容,而事務 B 插入一條到數據庫后提交了。此時事務 A 又讀了一次數據庫內容,這時數據庫現了多一條數據稱為幻讀
SERIALIZABLE (可串行化)最高的隔離級別
在讀取的每一行數據都上鎖。導致導量的超時和等待鎖的問題。
| 未提交讀 | √ | √ | √ | x | 
| 提交讀 | x | √ | √ | x | 
| 可重復讀 | x | x | √ | x | 
| 可串行化 | x | x | x | √ | 
選擇哪種模式其實是一種博弈的過程,數據庫的事務隔離越嚴格,并發副作用越小,但付出的代價也就越大,因為事務隔離實質上就是使事務在一定程度上“串行化”進行,這顯然與“并發”是矛盾的。
自動提交(AUTOCOMMIT)
MySQL 默認采用自動提交(AUTOCOMMIT)模式。如果不顯式地開始一個事務,則每個事務都被當做一個事務進行提交操作。MyISAM 在執行查詢語句(select)前,會自動給涉及的所有表加讀鎖,在執行更新操作(update、delete、insert等)前,會自動給涉及的表加寫鎖,這個過程并不需要直接用 lock table 命令給 MyISAM 表顯示加鎖。MyISAM 在自動加鎖的情況下,總是一次獲得 sql 語句所需要的全部鎖,所以顯示鎖表的時候,必須同時取得所有涉及表的鎖,這也正是 MyISAM 表不會出現死鎖(deadlock)的原因。
查看自動提交模式類型show variables like 'autocommit'
設置自動提交模式set autocommit = 1在事務的執行過程中,隨時都可以執行鎖定,鎖只有 COMMIT 或 ROLLBACK 才會釋放
MySQL 可以使用 SET TRANSACTION ISOLATION LEVEL 命令設置隔離級別
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
鎖
死鎖
死鎖是指兩個或者多個事務在同一個資源上互相占用,并請求鎖定對方占用的資源,從而出現惡性循環的現象。
死鎖產生的原因
因為系統資源不足。
進程運行推進的順序不合適。
資源分配不當等。
如果系統資源充足,進程的資源請求都能夠得到滿足,死鎖出現的可能性就很低,否則 就會因爭奪有限的資源而陷入死鎖。其次,進程運行推進順序與速度不同,也可能產生死鎖。
死鎖產生的條件
互斥條件:一個資源每次只能被一個進程使用。
占有且等待:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
不可強行占有:進程已獲得的資源,在末使用完之前,不能強行剝奪。
循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關系。這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立。
死鎖的預防
破幻死鎖產生的必要條件
檢測到死鎖的循環依賴,放棄鎖的請求
等待鎖超市,放棄鎖
樂觀鎖
樂觀鎖(Optimistic Lock),顧名思義,就是很樂觀,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在提交更新的時候會判斷一下在此期間別人有沒有去更新這個數據。樂觀鎖適用于讀多寫少的應用場景,這樣可以提高吞吐量。
樂觀鎖:假設不會發生并發沖突,只在提交操作時檢查是否違反數據完整性。
樂觀鎖的實現方式
使用數據版本(Version)記錄機制實現,這是樂觀鎖最常用的一種實現方式。何謂數據版本?即為數據增加一個版本標識,一般是通過為數據庫表增加一個數字類型的 “version” 字段來實現。當讀取數據時,將version字段的值一同讀出,數據每更新一次,對此version值加一。當我們提交更新的時候,判斷數據庫表對應記錄的當前版本信息與第一次取出來的version值進行比對,如果數據庫表當前版本號與第一次取出來的version值相等,則予以更新,否則認為是過期數據。
使用時間戳(timestamp)。樂觀鎖定的第二種實現方式和第一種差不多,同樣是在需要樂觀鎖控制的table中增加一個字段,名稱無所謂,字段類型使用時間戳(timestamp), 和上面的version類似,也是在更新提交的時候檢查當前數據庫中數據的時間戳和自己更新前取到的時間戳進行對比,如果一致則OK,否則就是版本沖突。
應用場景樂觀鎖適用于寫比較少的情況下(多讀場景) ,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。
悲觀鎖
悲觀鎖(Pessimistic Lock),顧名思義,就是很悲觀,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。
悲觀鎖:假定會發生并發沖突,屏蔽一切可能違反數據完整性的操作。
應用場景一般多寫的場景下用悲觀鎖就比較合適
最后,再附上我歷時三個月總結的?Java 面試 + Java 后端技術學習指南,這是本人這幾年及春招的總結,目前,已經拿到了大廠offer,拿去不謝!
下載方式
1.?首先掃描下方二維碼
2.?后臺回復「Java面試」即可獲取
總結
以上是生活随笔為你收集整理的必须懂的 MySQL 的事务与隔离级别的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 为什么程序员都不喜欢使用switch,而
- 下一篇: Java 必知必会的 20 种常用类库和
