隔離性是當多個用戶併發訪問數據庫時,好比同時操做同一張表時,數據庫爲每個用戶開啓的事務,不能被其餘事務的操做所幹擾,多個併發事務之間要相互隔離css
讀未提交
:隔離級別最低的一種事務級別。在這種隔離級別下,會引起髒讀、不可重複讀和幻讀。mysql
讀已提交
讀到的都是別人提交後的值。這種隔離級別下,會引起不可重複讀和幻讀,但避免了髒讀。sql
可重複讀
這種隔離級別下,會引起幻讀,但避免了髒讀、不可重複讀。數據庫
串行化
是最嚴格的隔離級別。在Serializable隔離級別下,全部事務按照次序依次執行。髒讀、不可重複讀、幻讀都不會出現。session
SHOW VARIABLES LIKE 'tx_isolation';
併發
查看全局的事務隔離級別app
SHOW GLOBAL VARIABLES LIKE 'tx_isolation';
性能
使用系統變量查詢spa
SELECT @@global.tx_isolation;
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
日誌
MySql經常使用命令
查詢隔離級別select @@tx_isolation;
設置手動提交set autocommit=0 ;
查看當前事務自動提交模式select @@autocommit;
設置隔離級別set tx_isolation = 'READ-COMMITTED';
查詢表的狀態show table status like 'test1';
修改表的存儲引擎alter table test1 engine = INNODB
查看是否開啓日誌show variables like 'log_bin';
查看日誌狀態show master status;
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';
在多個事務併發作數據庫操做的時候,若是沒有有效的避免機制,就會出現種種問題。大致上有如下問題:
髒讀
指一個事務讀取了另一個事務未提交的數據。
具體看後文案例介紹
不可重複讀
指在一個事務內讀取表中的某一行數據,屢次讀取結果不一樣。
不可重複讀和髒讀的區別是,髒讀是讀取前一事務未提交的髒數據,不可重複讀是從新讀取了前一事務已提交的數據。
具體看後文案例介紹
幻讀(虛讀)
指在一個事務內讀取到了別的事務插入的數據,致使先後讀取不一致。
如下都是採用mysql數據庫
下面實際操做中使用到的一些併發控制語句,可看上面的操做介紹
做爲演示:product表(產品表)
產品ID 產品名稱 產品價格 產品數量 .
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。但這個過程當中事務並未提交結束。
3.3事務隔離級別設置爲Repeatable Read(mysql默認級別)
查詢事務隔離級別
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纔對。接下來咱們再提升一個事務隔離級別。3.4事務隔離級別設置爲Serializable
查詢事務隔離級別
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的操做。這樣就避免了上述三個問題了。
問題自己
回到問題的自己,其實咱們並不須要將事務提到這麼高。
問題的自己就是,當咱們讀完了的時候,就要在上面加鎖。咱們不但願別人可以去讀它。由於別人讀到了count,就會修改count的值,並寫進去。因此咱們在select 操做的時候,加上for update。這時候就會把這行操做給鎖掉了。那麼另一我的也進行相同的操做,也表示select 出來的count須要進行update,須要鎖住。
- select p.productName,p.productCount from product p where p.productId=1 for update;
- 在實際開發過程當中,這樣的加鎖行爲,是很是的耗系統性能的
本章節主要介紹了數據庫中事務的ADID特性中的
隔離性
,在沒有隔離的狀況下會發生什麼問題,相信你們經過本章,對數據庫事務中的隔離性
有了必定的瞭解,下篇文章咱們將介紹數據庫中的悲觀鎖與樂觀鎖
。