事務隔離性和隔離級別

隔離性是當多個用戶併發訪問數據庫時,好比同時操做同一張表時,數據庫爲每個用戶開啓的事務,不能被其餘事務的操做所幹擾,多個併發事務之間要相互隔離css

事務的隔離級別有哪些?

1、概念

  • Read uncommitted(讀未提交)
  • Read Committed(讀已提交)
  • Repeatable Reads(可重複讀)
  • Serializable(串行化)

Read uncommitted

讀未提交:隔離級別最低的一種事務級別。在這種隔離級別下,會引起髒讀、不可重複讀和幻讀。mysql

Read Committed

讀已提交讀到的都是別人提交後的值。這種隔離級別下,會引起不可重複讀和幻讀,但避免了髒讀。sql

Repeatable Reads

可重複讀這種隔離級別下,會引起幻讀,但避免了髒讀、不可重複讀。數據庫

Serializable

串行化是最嚴格的隔離級別。在Serializable隔離級別下,全部事務按照次序依次執行。髒讀、不可重複讀、幻讀都不會出現。session

 

 

 

2、操做

查看事務隔離級別

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;

3.2 設置MysQL的事務隔離級別

語法

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數據庫

3、案例

下面實際操做中使用到的一些併發控制語句,可看上面的操做介紹

做爲演示:product表(產品表)

  產品ID        產品名稱        產品價格        產品數量   .

productId productName productPrice productCount
1 xiaomi 1999 100
 

帶着上面的問題咱們來看一下,事務在沒有隔離性的狀況下,會引起哪些問題?

同時打開兩個窗口模擬2個用戶併發訪問數據庫

3.1事務隔離級別設置爲read uncommitted

查詢事務隔離級別

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的髒讀 !

3.2事務隔離級別設置爲Read Committed

查詢事務隔離級別

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特性中的隔離性,在沒有隔離的狀況下會發生什麼問題,相信你們經過本章,對數據庫事務中的隔離性有了必定的瞭解,下篇文章咱們將介紹數據庫中的悲觀鎖與樂觀鎖

相關文章
相關標籤/搜索