mysql淺談--事務ACID特性

邱志強 發表於 2020-09-15

mysql

  MySQL 是最流行的關係型資料庫管理系統,在 WEB 應用方面 MySQL 是最好的 RDBMS(Relational Database Management System:關聯式資料庫管理系統)應用軟體之一。

mysql結構

 

    mysql淺談--事務ACID特性

    如上圖所示,可分為使用者連線執行緒 -> 服務層 -> 儲存引擎

    使用者連線執行緒:處理客戶端連線、授權、使用者認證等。

    服務層:處理sql語句的解析、快取的處理和函式的實現等

    儲存引擎:對於資料的儲存和提取(innodb、NDB Cluster支援事務,Mylsam、Memory不支援事務)。

    如無特殊說明,後文中描述的內容都是基於InnoDB。

 ACID事務特性

  mysql由start transaction標識事務的開啟,commit提交事務,rollback回滾事務,mysql在預設情況下開啟事務,即autocommit模式,在這種模式下,每一個sql語句都會被當成一個事務執行提交操作。當然也可以將autocommit的開關關上,需要注意的事,autocommit引數針對的事連線,修改引數只會對當前連線生效,如需全域性修改,請修改啟動配置檔案。

    mysql當中,當執行一些特殊的語句的會後,會強制事務的提交,比如DDL語句(create table/drop table/alter/table),常用的增刪改查操作都不會強制提交事務

  •   原子性(Atomicity)

      原子性是指一個事務不可分割的一個工作單位,要麼都成功,要麼都失敗。針對單個事務而言

      實現原理:undo log(回滾日誌,由儲存引擎實現)

        當事務對資料庫進行修改時,innodb會生成對應的undo log記錄,記錄sql執行相關資訊。當事務失敗呼叫rollback回滾時,會根據undolog中的資訊進行反向操作,將資料回滾到事務開啟之前的狀態。

  •    一致性(Consistency)

    一致性指的是事務執行前後資料的完整性沒有被破壞,包括實體完整性(如行的主鍵存在且唯一)、列完整性(如欄位的型別、大小、長度要符合要求)、外來鍵約束、使用者自定義完整性(如轉賬前後,兩個賬戶餘額的和應該不變)等等。

    一致性是事務的終極目標,其他三個特性都是為一致性所服務的

    資料庫實現一致性的措施體現:

      不允許向整形列插入字串值、字串長度不能超過列的限制等

  •   隔離性(Isolation) 

     隔離性指的是多個事務同時執行的時候,每個事務內部都應該與其他事務是隔離的,不能互相干擾。

       資料庫的隔離級別:讀未提交(RU)、讀已提交(RC)、可重複讀(RR)、序列化也叫序列化(S)

     實現原理:讀讀之間(MVCC多版本併發控制協議)、讀寫之間(鎖機制)

      1、MVCC:MVCC是一種樂觀鎖的體現,主要是通過兩個隱藏列實現(事務版本號和undolog指標,也是undolog版本鏈),使用者在某一時刻對整個事務系統進行快照,之後再進行讀操作時,會將讀取到的事務中的事務版本號和快照比較,從而判斷資料對該快照是否可見,即對打快照時的事務是否可見。RR隔離級別下,事務在事務開始的時候進行快照動作,一直到事務提交都不會重新進行快照。RC則是每次select操作之前會重新建立快照,這就導致RC可能會在第二次select的時候讀到其他事務提交得資料,所以RC情況下可以避免髒讀問題可是無法避免重複讀和幻讀問題。

     2、鎖機制:mysql鎖可以分為共享鎖(lock in share mode)、排它鎖(for update)、意向鎖(意向共享和意向排他)、間隙鎖(Gap lock),共享鎖、排它鎖是行鎖,鎖粒度小,效能好,意向鎖是表鎖,是資料庫自身的行為,不需要人工干預,在事務結束後會自行解除,多用在innodb當中,意向鎖主要解決事務開始時遍歷所有行的鎖持有情況從而導致效能較低的問題,事務在檢查行鎖之前會檢查意向鎖是否存在,存在則阻塞執行緒.

    意向鎖協議: 

    •   事務要獲取表A某些行的S鎖必須要獲取表A的IS鎖(意向共享鎖)
    •   事務要獲取表A某些行的X鎖必須要獲取表A的IX鎖(意向排他鎖)

    間隙鎖:

      innodb下間隙鎖的產生需要產生三個條件:

        1、隔離級別為RR(mysql預設,不改即為這個)

        2、當前讀(非快照讀)

        3、查詢條件能夠走索引(這裡提一句:mysql行鎖(間隙鎖也是行鎖)鎖的是索引,所以當查詢未使用索引的情況下,innodb會使用表鎖,這就會導致一些使用相同索引鍵的查詢也會出現鎖衝突

      注意:innodb使用一個相等條件請求對一個不存在的記錄加鎖的時候,也會產生間隙鎖

      間隙鎖的作用:

        當前讀幻讀的解決方法:間隙鎖可以鎖定一個範圍內的多條資料,防止事務執行的時候其他事務往這個範圍內插入資料,導致幻讀,這是主要目的。

      

  • 永續性(Durability)

    永續性指的是事務一單提交,它對資料庫產生的改變應該是持久的(單個事務而言).

    實現原理:redo log(重做日誌,儲存引擎實現)

      在innodb當中,資料是存放在磁碟上的,但是如果每次查詢資料都需要讀磁碟的話,效率會相當低。為此,innodb提供了一個快取機制--Buffer Pool(簡稱BP),BP中包含了磁碟中部分資料的對映,作為訪問資料庫的快取。

        當讀資料的時候,先讀BP,BP沒有在讀磁碟,然後將資料放入BP。

        當寫資料的時候,先寫BP,BP會將資料定期重新整理到磁碟當中(刷髒)

      上面寫資料就會產生一個問題,當我們的機子當機了,BP資料還未刷到磁碟中那資料不就丟失啦?事務的永續性就得不到保證

      為了解決這個問題:redo log 引入解決這個問題:

        當資料修改時,會先記錄在redo log 中。然後再寫入BP中,當事務提交的時候,就會呼叫fsync介面對redolog進行刷盤(落磁碟),如果mysql當機,就可以在重啟的時候讀取redolog的日誌恢復資料庫中的資料.

        既然redolog也要進行磁碟IO,為什麼比BP快呢?

        兩個原因:

          1、BP是隨機IO,每次修改的位置隨機,redoLog屬於追加操作,順序IO.

          2、BP是以頁(Page)為單位進行磁碟操作的,但是redolog只是做真正需要寫入的部分,相對BP來講,會少很多無效的IO.

 

 

 

 最後提一嘴binog和redo log的區別:

    1、redo log儲存引擎實現、binlog服務層實現(可參照第一張圖,不太擅長畫圖,sorry……)

    2、redo log寫入的時機比較多,各種修改都會觸發,只是在事務提交的時候落磁碟而已。binlog則只會在事務提交的時候寫入。

    3、binlog為二進位制日誌,根據引數不同可能是sql或者資料。redolog則是物理日誌,內容基於Page。

 

 

第一次寫一篇比較完整的部落格,完全根據自己的想法走,要是哪個位置寫的不太對,歡迎大家一起探討提高,感謝每一個路過的人。