動態

詳情 返回 返回

MySQL 事務詳解 - 動態 詳情

MySQL 事務

數據庫事務指的是一組數據操作,事務內的操作要麼就是全部成功,要麼就是全部失敗,如果部分成功,那麼已成功的必須回滾,恢復數據的原始狀態。

假設一個網購付款的操作,用户付款後要涉及到訂單狀態更新、扣庫存以及其他一系列動作,這就是一個事務,如果一切正常那就相安無事,一旦中間有某個環節異常,那整個事務就要回滾,總不能更新了訂單狀態但是不扣庫存吧,這問題就大了。

事務具有原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)四個特性,簡稱 ACID。

一、事務的基本要素(ACID)

  1、原子性(Atomicity):事務開始後所有操作,要麼全部做完,要麼全部不做,不可能停滯在中間環節。事務執行過程中出錯,會回滾到事務開始前的狀態,所有的操作就像沒有發生一樣。也就是説事務是一個不可分割的整體,就像化學中學過的原子,是物質構成的基本單位。

   2、一致性(Consistency):事務開始前和結束後,數據庫的完整性約束沒有被破壞 。比如A向B轉賬,不可能A扣了錢,B卻沒收到。

   3、隔離性(Isolation):同一時間,只允許一個事務請求同一數據,不同的事務之間彼此沒有任何干擾。比如A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉賬。

   4、持久性(Durability):事務完成後,事務對數據庫的所有更新將被保存到數據庫,不能回滾。
  

二、事務的併發問題

  1、髒讀:事務A讀取了事務B更新的數據,然後B回滾操作,那麼A讀取到的數據是髒數據

  2、不可重複讀:事務 A 多次讀取同一數據,事務 B 在事務A多次讀取的過程中,對數據作了更新並提交,導致事務A多次讀取同一數據時,結果 不一致。

  3、幻讀:一個事物內多次執行同一條sql,返回的結果集不一樣。 比如一條select語句執行兩次,第二次返回了第一次查詢不存在的數據。

4、丟失修改(Lost to modify): 指在一個事務讀取一個數據時,另外一個事務也訪問了該數據,那麼在第一個事務中修改了這個數據後,第二個事務也修改了這個數據。這樣第一個事務內的修改結果就被丟失,因此稱為丟失修改。 例如:事務 1 讀取某表中的數據 A=20,事務 2 也讀取 A=20,事務 1 修改 A=A-1,事務 2 也修改 A=A-1,最終結果 A=19,事務 1 的修改被丟失。

  小結:不可重複讀的和幻讀很容易混淆,不可重複讀側重於修改,幻讀側重於新增或刪除。解決不可重複讀的問題只需鎖住滿足條件的行,解決幻讀需要間隙鎖+MVCC
  

三、事務隔離級別

SQL 標準定義了四種隔離級別,MySQL 全都支持。這四種隔離級別分別是:

  • 讀未提交(READ UNCOMMITTED)
  • 讀提交 (READ COMMITTED)
  • 可重複讀 (REPEATABLE READ)
  • 串行化 (SERIALIZABLE)
    從上往下,隔離強度逐漸增強,性能逐漸變差。採用哪種隔離級別要根據系統需求權衡決定,其中,可重複讀是 MySQL 的默認級別。

事務隔離其實就是為了解決上面提到的髒讀、不可重複讀、幻讀這幾個問題,下面展示了 4 種隔離級別對這三個問題的解決程度。

隔離級別 髒讀 不可重複度 幻讀
讀未提交 可能 可能 可能
讀已提交 不可能 可能 可能
可重複度 不可能 不可能 可能(v5.6以後是不可能)
串行化 不可能 不可能 不可能

v5.6版本以後可重複讀級別就解決了幻讀問題。

讀提交解決了髒讀問題,行鎖解決了併發更新的問題。並且 MySQL 5.6以後 在可重複讀級別解決了幻讀問題,是通過行鎖和間隙鎖的組合 Next-Key 鎖實現的。:

To prevent phantoms, InnoDB uses an algorithm called next-key locking that combines index-row locking with gap locking. InnoDB performs row-level locking in such a way that when it searches or scans a table index, it sets shared or exclusive locks on the index records it encounters. Thus, the row-level locks are actually index-record locks. In addition, a next-key lock on an index record also affects the “gap” before the index record. That is, a next-key lock is an index-record lock plus a gap lock on the gap preceding the index record. If one session has a shared or exclusive lock on record R in an index, another session cannot insert a new index record in the gap immediately before R in the index order.

串行化

相當於單線程,後一個事務的執行必須等待前一個事務結束。

打開連個客户端, 回話1執行update語句, 提交之前打開客户端2執行update語句或者select都會提示失敗,鎖超時。
因為事物1執行後update語句整個表被加上了獨佔鎖,其他事物無法執行任何操作

    #session 1
    
    SET autocommit=0;
    SET transaction isolation level SERIALIZABLE;
    
    START TRANSACTION;
    
    UPDATE test SET score = 11 WHERE id=10
    
    COMMIT
    
    #sesssion 2
    
    SET autocommit=0;
    
    SET session transaction isolation level SERIALIZABLE;
    
    START TRANSACTION;
    
    UPDATE test SET score = 25 WHERE id=20
    
    COMMIT
    

 補充

  1、事務隔離級別為讀提交時,寫數據只會鎖住相應的行

  2、事務隔離級別為可重複讀時,如果檢索條件有索引(包括主鍵索引)的時候,默認加鎖方式是next-key 鎖;如果檢索條件沒有索引,更新數據時會鎖住整張表。一個間隙被事務加了鎖,其他事務是不能在這個間隙插入記錄的,這樣可以防止幻讀。

  3、事務隔離級別為串行化時,讀寫數據都會鎖住整張表

  4、隔離級別越高,越能保證數據的完整性和一致性,但是對併發性能的影響也越大。

  5、關於next-key 鎖可以參考鏈接:https://segmentfault.com/a/1190000040198549

Add a new 評論

Some HTML is okay.