咱們在上一章節中介紹過數據庫的帶你瞭解數據庫中事務的ACID特性 的相關用法。本章節主要來介紹下數據庫中一個很是重要的知識點事務的隔離級別
。若有錯誤還請你們及時指出~ mysql
問題:git
如下都是採用mysql數據庫
在多個事務併發作數據庫操做的時候,若是沒有有效的避免機制,就會出現種種問題。大致上有如下問題:github
在併發事務沒有進行隔離的狀況下,會發生以下問題。sql
髒讀
指一個事務讀取了另一個事務未提交的數據。數據庫
具體看後文案例介紹
編程
不可重複讀
指在一個事務內讀取表中的某一行數據,屢次讀取結果不一樣。
不可重複讀和髒讀的區別是,髒讀是讀取前一事務未提交的髒數據,不可重複讀是從新讀取了前一事務已提交的數據。微信
具體看後文案例介紹
session
幻讀(虛讀)
指在一個事務內讀取到了別的事務插入的數據,致使先後讀取不一致。併發
具體看後文案例介紹
性能
讀未提交
:隔離級別最低的一種事務級別。在這種隔離級別下,會引起髒讀、不可重複讀和幻讀。
讀已提交
讀到的都是別人提交後的值。這種隔離級別下,會引起不可重複讀和幻讀,但避免了髒讀。
可重複讀
這種隔離級別下,會引起幻讀,但避免了髒讀、不可重複讀。
串行化
是最嚴格的隔離級別。在Serializable隔離級別下,全部事務按照次序依次執行。髒讀、不可重複讀、幻讀都不會出現。
SHOW VARIABLES LIKE 'tx_isolation';
查看全局的事務隔離級別
SHOW GLOBAL VARIABLES LIKE 'tx_isolation';
使用系統變量查詢
SELECT @@global.tx_isolation;
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL { REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED | SERIALIZABLE }
GLOBAL
:設置全局的事務隔離級別SESSION
:設置當前session的事務隔離級別,若是語句沒有指定GLOBAL或SESSION,默認值爲SESSION
SET GLOBAL tx_isolation='REPEATABLE-READ';
SET SESSION tx_isolation='SERIALIZABLE';
下面實際操做中使用到的一些併發控制語句,可看上面的操做介紹
做爲演示:product表
productId | productName | productPrice | productCount |
---|---|---|---|
1 | xiaomi | 1999 | 100 |
帶着上面的咱們來看一下,事務在沒有隔離性的狀況下,會引起哪些問題?
同時打開兩個窗口模擬2個用戶併發訪問數據庫
查詢事務隔離級別
SELECT @@tx_isolation;
設置隔離級別爲未提交讀:
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
注意:須要同時修改兩個窗口的事務隔離級別
如下咱們以兩位用戶搶小米手機爲例
時間軸 | 事務A | 事務B |
---|---|---|
T1 | start transaction; | |
T2 | select p.productName,p.productCount from product p where p.productId=1;(productCount =100) | |
T3 | start transaction; | |
T4 | select p.productName,p.productCount from product p where p.productId=1;(productCount =100) | |
T5 | update product set productCount = 99 where productId = 1; | |
T6 | select p.productName,p.productCount from product p where p.productId=1;(productCount =99) | |
T7 | ROLLBACK; | |
T8 | select p.productName,p.productCount from product p where p.productId=1;(productCount =100) |
T1—— A用戶開啓事務,start transaction;
T2—— A用戶查詢當前小米手機剩餘數量,select p.productName,p.productCount from product p where p.productId=1;此時數量顯示爲100。
T3——B用戶開啓事務,start transaction;
T4——B用戶查詢當前小米手機剩餘數量,select p.productName,p.productCount from product p where p.productId=1;此時數量顯示爲100。
T5—— B用戶購買了一臺小米手機,update product set productCount = 99 where productId = 1; 此時只修改數據並未提交事務。
T6—— A用戶刷新頁面,select p.productName,p.productCount from product p where p.productId=1;此時數量顯示爲99。
T7—— B用戶購買失敗,回滾事務。
T8—— A用戶查詢當前小米手機剩餘數量,select p.productName,p.productCount from product p where p.productId=1;此時數量顯示爲100。
事務A讀取了未提交的數據,事務B的回滾,致使了事務A的數據不一致,致使了事務A的髒讀
!
查詢事務隔離級別
SELECT @@tx_isolation;
更改數據庫隔離級別,設置隔離級別爲提交讀:
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
注意:須要同時修改兩個窗口的事務隔離級別
時間軸 | 事務A | 事務B |
---|---|---|
T1 | start transaction; | |
T2 | select p.productName,p.productCount from product p where p.productId=1;(productCount =100) | |
T3 | start transaction; | |
T4 | select p.productName,p.productCount from product p where p.productId=1;(productCount =100) | |
T5 | update product set productCount = 99 where productId = 1; | |
T7 | select p.productName,p.productCount from product p where p.productId=1;(productCount =100) | |
T6 | commit; | |
T8 | select p.productName,p.productCount from product p where p.productId=1;(productCount =99) |
這裏就再也不對流程作過多贅述。
能夠看到避免了髒讀
現象,可是卻出現了,一個事務尚未結束,就發生了不可重複讀問題,即事務A來講 productCount從 100->100->99。但這個過程當中事務並未提交結束。
查詢事務隔離級別
SELECT @@tx_isolation;
更改數據庫隔離級別,設置隔離級別爲可重複讀:
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
注意:須要同時修改兩個窗口的事務隔離級別
時間軸 | 事務A | 事務B |
---|---|---|
T1 | start transaction; | |
T2 | select p.productName,p.productCount from product p where p.productId=1;(productCount =100) | |
T3 | start transaction; | |
T4 | select p.productName,p.productCount from product p where p.productId=1;(productCount =100) | |
T5 | update product set productCount = 99 where productId = 1; | |
T7 | select p.productName,p.productCount from product p where p.productId=1;(productCount =100) | |
T6 | commit; | |
T8 | select p.productName,p.productCount from product p where p.productId=1;(productCount =100) |
這裏就再也不對流程作過多贅述。
能夠看到可重複讀
隔離級別避免了髒讀
,不可重複讀
的問題,可是出現了幻讀
現象。事務A查詢到的小米數量等於100,可是事務B修改了數量爲99,可是事務A讀取到的值仍是100。當事務A去減1等於99時,是錯誤的,此時應該是99-1=98纔對。接下來咱們再提升一個事務隔離級別。
查詢事務隔離級別
SELECT @@tx_isolation;
更改數據庫隔離級別,設置隔離級別爲串行化:
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
時間軸 | 事務A | 事務B |
---|---|---|
T1 | start transaction; | |
T2 | start transaction; | |
T2 | select p.productName,p.productCount from product p where p.productId=1;(productCount =100); | |
T4 | update product set productCount = 99 where productId = 1;(等待中..) |
這裏就再也不對流程作過多贅述。
在咱們Serializable隔離級別中,咱們能夠看到事務B去作修改動做時卡主了,不能向下執行。這是由於:給事務A的select操做上了鎖,因此事務B去修改值的話,就會被卡主。只有當事務A操做執行完畢,纔會執行事務B的操做。這樣就避免了上述三個問題了。
select p.productName,p.productCount from product p where p.productId=1 for update;
PS: 在實際開發過程當中,這樣的加鎖行爲,是很是的耗系統性能的。下一章節咱們未來介紹
悲觀鎖與樂觀鎖
本章節主要介紹了數據庫中事務的ADID特性中的隔離性
,在沒有隔離的狀況下會發生什麼問題,相信你們經過本章,對數據庫事務中的隔離性
有了必定的瞭解,下篇文章咱們將介紹數據庫中的悲觀鎖與樂觀鎖
。
歡迎關注公衆號: Coder編程
獲取最新原創技術文章和相關免費學習資料,隨時隨地學習技術知識!
歡迎你們關注並Star~