mysql(InnoDB)事務隔離級別(READ COMMITTED) 與 鎖,MVCC

READ COMMITTED

(提交讀)html

  1. 瞭解了以前 READ UNCOMMITTED 隔離級別是如何加鎖的, 而且在文章中, 已經知道 READ COMMITTED 隔離級別能夠解決髒讀的問題, 那接下來, 對於 READ COMMITTED 隔離級別, 試想一下若是讓你用鎖來設計, 你會怎麼作?mysql

    • 既然READ COMMITTED 隔離級別能夠解決髒讀的問題, 也就是他可讓事務只能讀其餘事務已提交的的記錄。
    • 若是用鎖機制來實現該隔離級別:
      試想一下, 當在事務A中讀取數據D的時候, 假設D以前已經在事務B中了, 而且事務B中對數據D作了修改, 可是事務B尚未完成(commit/rollback), 那如何讓事務A沒法讀取數據D呢?
      當事務B在對數據D操做的時候, 假設給數據D加上了行級的排他鎖(X lock), 那事務A天然只能阻塞等事務A完成後才能讀取數據D了!
    • 數據庫這樣作的話確實實現了READ COMMITTED隔離級別的效果, 也就避免了髒讀, 但問題是這是一種很低效的作法, 由於對於大部分應用來講, 讀操做是多於寫操做的, 當寫操做加鎖時, 那麼讀操做所有被阻塞, 這樣在大用戶量高併發的狀況下, 會直接下降數據庫的讀效率。
  2. 那麼, 既然用鎖機制實現該隔離級別是低效的作法, 數據庫是如何作的?
    以前在相關MVCC的文章中能夠獲得答案: 數據庫是使用了 排他鎖+MVCC 的機制來實現該隔離級別的, 而不是單純的使用鎖或者單純的使用MVCC

READ COMMITTED與鎖 測試

  1. 數據表結構以下:sql

    mysql> select * from test_transaction;
    +----+---------------+-----+--------+--------------------+
    | id | user_name     | age | gender | desctiption        |
    +----+---------------+-----+--------+--------------------+
    |  1 | 金剛狼     | 127 |      2 | 我有一雙鐵爪 |
    |  2 | 鋼鐵俠-rym | 120 |      1 | 我有一身鐵甲 |
    |  3 | 綠巨人     |   0 |      2 | 我有一身肉    |
    +----+---------------+-----+--------+--------------------+
    3 rows in set (0.00 sec)
     
    mysql>
  2. 從新設置客戶端1事務隔離級別爲read committed: SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;數據庫

    mysql> SELECT @@SESSION.tx_isolation;
    +------------------------+
    | @@SESSION.tx_isolation |
    +------------------------+
    | REPEATABLE-READ        |
    +------------------------+
    1 row in set (0.00 sec)
     
    mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
    Query OK, 0 rows affected (0.00 sec)
     
    mysql> SELECT @@SESSION.tx_isolation;
    +------------------------+
    | @@SESSION.tx_isolation |
    +------------------------+
    | READ-COMMITTED         |
    +------------------------+
    1 row in set (0.00 sec)
     
    mysql>
  3. 再從新打開一個客戶端2並設置事務隔離級別爲read committed;
  4. 客戶端1中打開事務, 而後更改數據, 先不提交; 而後在客戶端2中打開事務, 讀取客戶端1中還沒有提交的那條被修改數據
    clipboard.png
  5. 結果發如今客戶端2中能夠正常讀取到那條數據, 只不過, 那條數據並非被客戶端1事務中修改後的數據, 而是最初的穩定數據, 這就避免了髒讀!!
  6. 對於該隔離級別修改數據時使用的鎖類型, 其分析方法, 和以前一篇MySQL(INNODB引擎)事務READ UNCOMMITTED隔離級別和鎖的關係 是同樣的:segmentfault

    • 能夠在客戶端1的事務在修改數據而且未提交時, 在客戶端2中對同一數據進行修改, 而後在客戶端2阻塞階段經過
      查看錶的加鎖狀況: select * from information_schema.INNODB_LOCKS;,
      事務狀態: select * from information_schema.INNODB_TRX;,
      進行分析, 結果就不展現了, 能夠自行測試一下, 該隔離級別修改數據時使用的也是排他鎖, 而且客戶端2的修改語句會鎖等待~
      (和以前分析READ UNCOMMITTED隔離級別同樣, 既然使用了排他鎖, 居然別的事務還能讀取, 這特麼不就又違反了排他鎖的特性麼? 仍是那句話, 另外一個事務在讀取的時候並不會加鎖, 而是用的MVCC機制讀取的鏡像)
  7. 小結:
    InnoDB在該隔離級別(READ COMMITTED)寫數據是使用排他鎖, 讀取數據不加鎖而是使用了MVCC機制, 這樣就能夠大大提升併發讀寫效率, 寫不影響讀, 由於讀並未加鎖, 讀的是記錄的鏡像版本!!
相關文章
相關標籤/搜索