1. 程式人生 > >mysql的併發處理機制_上篇

mysql的併發處理機制_上篇

    回來寫部落格,少年前端時間被django迷了心魄

1 什麼是MVCC 

      MVCC全稱是: Multiversion concurrency control,多版本併發控制,提供併發訪問資料庫時,對事務內讀取的到的記憶體做處理,用來避免寫操作堵塞讀操作的併發問題。       舉個例子,程式設計師A正在讀資料庫中某些內容,而程式設計師B正在給這些內容做修改(假設是在一個事務內修改,大概持續10s左右),A在這10s內 則可能看到一個不一致的資料,在B沒有提交前,如何讓A能夠一直讀到的資料都是一致的呢?       有幾種處理方法,第一種: 基於鎖的併發控制,程式設計師B開始修改資料時,給這些資料加上鎖,程式設計師A這時再讀,就發現讀取不了,處於等待情況,只能等B操作完才能讀資料,這保證A不會讀到一個不一致的資料,但是這個會影響程式的執行效率。還有一種就是:MVCC,每個使用者連線資料庫時,看到的都是某一特定時刻的資料庫快照,在B的事務沒有提交之前,A始終讀到的是某一特定時刻的資料庫快照,不會讀到B事務中的資料修改情況,直到B事務提交,才會讀取B的修改內容。       一個支援MVCC的資料庫,在更新某些資料時,並非使用新資料覆蓋舊資料,而是標記舊資料是過時的,同時在其他地方新增一個數據版本。因此,同一份資料有多個版本儲存,但只有一個是最新的。       MVCC提供了 時間一致性的 處理思路,在MVCC下讀事務時,通常使用一個時間戳或者事務ID來確定訪問哪個狀態的資料庫及哪些版本的資料。讀事務跟寫事務彼此是隔離開來的,彼此之間不會影響。假設同一份資料,既有讀事務訪問,又有寫事務操作,實際上,寫事務會新建一個新的資料版本,而讀事務訪問的是舊的資料版本,直到寫事務提交,讀事務才會訪問到這個新的資料版本。       MVCC有兩種實現方式,第一種實現方式是將資料記錄的多個版本儲存在資料庫中,當這些不同版本資料不再需要時,垃圾收集器回收這些記錄。這個方式被PostgreSQL和Firebird/Interbase採用,SQL Server使用的類似機制,所不同的是舊版本資料不是儲存在資料庫中,而儲存在不同於主資料庫的另外一個數據庫tempdb中。第二種實現方式只在資料庫儲存最新版本的資料,但是會在使用undo時動態重構舊版本資料,這種方式被Oracle和MySQL/InnoDB使用。

2  Innodb的MVCC

      在Innodb db中,無論是聚簇索引,還是二級索引,每一行記錄都包含一個 DELETE bit,用於表示該記錄是否被刪除, 同時,聚簇索引還有兩個隱藏值:DATA_TRX_ID,DATA_ROLL_PTR。DATA _TRX_ID表示產生當前記錄項的事務ID,這個ID隨著事務的建立不斷增長;DATA _ROLL_PTR指向當前記錄項的undo資訊。
  1. 無論是聚簇索引,還是二級索引,只要其鍵值更新,就會產生新版本。將老版本資料deleted bti設定為1;同時插入新版本。
  2. 對於聚簇索引,如果更新操作沒有更新primary key,那麼更新不會產生新版本,而是在原有版本上進行更新,老版本進入undo表空間,通過記錄上的undo指標進行回滾。
  3. 對於二級索引,如果更新操作沒有更新其鍵值,那麼二級索引記錄保持不變。
  4. 對於二級索引,更新操作無論更新primary key,或者是二級索引鍵值,都會導致二級索引產生新版本資料。
  5. 聚簇索引設定記錄deleted bit時,會同時更新DATA_TRX_ID列。老版本DATA_TRX_ID進入undo表空間;二級索引設定deleted bit時,不寫入undo。
       MVCC只工作在REPEATABLE READ和READ COMMITED隔離級別下。READ UNCOMMITED不是MVCC相容的,因為查詢不能找到適合他們事務版本的行版本;它們每次都只能讀到最新的版本。SERIABLABLE也不與MVCC相容,因為讀操作會鎖定他們返回的每一行資料 。
在MVCC中,讀操作分為兩類:當前讀跟快照讀,當前讀返回最新記錄,會加鎖,保證該記錄不會被其他事務修改;快照讀,讀取的是記錄的某個版本(有可能是最新版本也有可能是舊版本),不加鎖。       快照讀:RU,RC,RR隔離級別下,select * from tbname where ....       當前讀:
  1. select * from tbname where ....  for update (加X鎖)
  2. select * from tbname where ....  lock in share mode(加S鎖)
  3. insert into tbname .... (加X鎖,注意如果有unique key的情況)
  4. delete from tbname ... (加X鎖)
  5. update tbname set ... where .. (加X鎖)

3 Two Phase Locking

      2-PL,也就是兩階段鎖,鎖的操作分為兩個階段:加鎖、解鎖。先加鎖,後解鎖,不相交。加鎖時,讀操作會申請並佔用S鎖,寫操作會申請並佔用X鎖,如果對所在記錄加鎖有衝突,那麼會處於等待狀態,知道加鎖成功才驚醒下一步操作。解鎖時,也就是事務提交或者回滾的時候,這個階段會釋放該事務中所有的加鎖情況,進行一一釋放鎖。      假設事務對記錄A和記錄B都有操作,那麼,其加鎖解鎖按照逐行加鎖解鎖順序,如下:
BEGIN
LOCK A
READ A
A:A+100
WRITE A
UNLOCK A
LOCK B
READ B
UNLOCK B
COMMIT
     兩階段鎖還有幾種特殊情況:conservative(保守)、strict(嚴格)、strong strict(強嚴格),這三種類型在加鎖和釋放鎖的處理有些不一樣。
  1. conservative
    • 在事務開始的時候,獲取需要的記錄的鎖,避免在操作期間逐個申請鎖可能造成的鎖等待,conservative 2PL 可以避免死鎖
  2. strict 
    • 僅在事務結束的時候(commit or rollback),才釋放所有 write lock,read lock 則正常釋放
  3. strong strict
    • 僅在事務結束的時候(commit or rollback),才釋放所有鎖,包括write lock 跟 read lock 都是結束後才釋放。

4 資料不一致情況

4.1 髒讀

    讀取未提交事務中修改的資料,稱為髒讀。     舉例,表格 A (name,age),記錄1為name='xinysu',age=188          這裡,事務2 中讀出來的資料是 (name,age)=('xinysu',299),這一條是 事務1中未提交的記錄,屬於髒資料。

4.2 丟失更新

      多個更新操作併發執行,導致某些更新操作資料丟失。       舉例,表格 A (name,age),記錄1為name='xinysu',age=188。併發2個更新操作如下:              正常情況下,如果是事務1操作後,age為288,事務2再進行288+100=388,但是實際上,事務2的操作覆蓋事務1的操作,造成了事務1的更新丟失。

4.3 不可重複讀

      同個事務多次讀取同一條存在的記錄,但是讀取的結構不一致,稱之為不可重複讀。       舉例,表格 A (name,age),記錄1為name='xinysu',age=188。操作如下:              事務1第一次讀出來的結構是name='xinysu',age=188,第二次讀出來的結果是name='xinysu',age=288,同個事務中,多次讀取同一行存在的記錄,但結果不一致的情況,則為不可重複讀。

4.4 幻讀

      同個事務多次讀取某段段範圍內的資料,但是讀取到底行數不一致的情況,稱之為幻讀。       舉例,表格 A (name,age),記錄1為name='xinysu',age=188。操作如下:              事務1中,第一次讀取的結果行數有1行,如果事務2執行的是delete,則事務1第二次讀取的為0行;如果事務2執行的是INSERT,則事務2第二次讀取的行數是2行,前後記錄數不一致,稱之為幻讀。

5 innodb的隔離級別

5.1 隔離級別介紹

  1. Read Uncommited
    • 簡稱 RU,讀未提交記錄,始終是讀最新記錄
    • 不支援快照讀,都是當前讀
    • 可能存在髒讀、不可重複讀、幻讀等問題;
  2. Read Commited
    • 簡稱 RC ,讀已提交記錄
    • 支援快照讀,讀取版本有可能不是最新版本
    • 支援當前讀,讀取到的記錄新增鎖
      • 不存在髒讀、不可重複讀
      • 存在幻讀問題;
  3. Read Repeatable
    • 簡稱 RR ,可重複讀記錄
    • 支援快照讀,讀取版本有可能不是最新版本
    • 支援當前讀,讀取到的記錄新增鎖,並且對讀取的範圍枷鎖,保證滿足查詢條件的記錄不能夠被insert進來
    • 不存在髒讀、不可重複讀及幻讀情況;
  4. Read Serializable
    • 簡稱 RS,序列化讀記錄
    • 不支援快照讀,都是當前讀
    • select資料新增S鎖,update\insert\delete資料新增X鎖
    • 併發度最差,除非明確業務需求及效能影響,才使用,一般不建議在innodb中應用

5.2 隔離級別測試   

測試各個隔離級別下的資料不一致情況。
1.檢視當前會話隔離級別
select @@tx_isolation;
 
2.檢視系統當前隔離級別
select @@global.tx_isolation;
 
3.設定當前會話隔離級別
set session transaction isolation level repeatable read;
 
4.設定系統當前隔離級別
set global transaction isolation level repeatable read;

5.2.1 Read Uncommitted

所有事務隔離級別設定: set session transaction isolation level read Uncommited ; 該隔離級別沒有的快照讀,所有讀操作都是讀最新版本,可以讀未提交事務的資料。 測試1:update資料不提交,另起查詢 測試結果:正常select可以查詢到不提交的事務內容,屬於髒讀   測試2:修改資料不提交,另起事務多次查詢 測試結果:同個事務多次讀取同一行記錄結果不一致,屬於重複讀   測試3:INSERT資料不提交,另起事務多次查詢 測試結果:同個事務多次讀取相同範圍的資料,但是行數不一樣,屬於幻讀 測試4:不同事務對同一行資料進行update 測試結果:由於INNODB有鎖機制,所有所有update都會持有X鎖互斥,並不會出現事務都提交成功情況下的丟失更新,所以四個隔離級別都可以避免丟失更新問題。 總結:沒有快照讀,都是當前讀,所有讀都是讀可以讀未提交記錄,存在髒讀、不可重複讀、幻讀等問題。

 5.2.2 Read Committed

所有事務隔離級別設定: set session transaction isolation level read committed ; 由於該隔離級別支援快照讀,不新增for update跟lock in share mode的select 查詢語句,使用的是快照讀,讀取已提交記錄,不新增鎖。所以測試使用當前讀的模式測試,新增lock in share mode,新增S鎖。 測試1:update資料不提交,另起查詢 測試結果:由於當前讀持有S鎖,導致update申請X鎖處於等待情況,無法更新,同個事務內的多次查詢結果一致,無髒讀及不可重複讀情況。 測試2:INSERT資料不提交,另起事務多次查詢 測試結果:同個事務多次讀取相同範圍的資料,但是行數不一樣,屬於幻讀(這裡注意,如果insert 分為beigin;commit,一直不commit的話,3的查詢會處於等待情況,因為它需要申請的S鎖被 insert的X鎖所堵塞) 測試3:快照讀測試 測試結果:同個事務多次讀取相同記錄,讀取的都是已提交記錄,不存在髒讀及丟失更新情況,但是存在不可重複讀及幻讀。

總結:支援快照讀,快照讀 不存在髒讀及丟失更新情況,但是存在不可重複讀及幻讀;而當前讀不存在髒讀、不可重複讀問題,存在幻讀問題。 

5.2.3 Read Repeatable

所有事務隔離級別設定: set session transaction isolation level repeatable read ; 由於該隔離級別支援快照讀,不新增for update跟lock in share mode的select 查詢語句,使用的是快照讀,不新增鎖。所以測試使用當前讀的模式測試,新增lock in share mode,新增S鎖。 測試1:update資料不提交,另起查詢 測試結果:由於當前讀持有S鎖,導致update申請X鎖處於等待情況,無法更新,同個事務內的多次查詢結果一致,無髒讀及不可重複讀情況。 測試2:INSERT資料不提交,另起事務多次查詢 測試結果:同個事務多次讀取相同範圍的資料,會有GAP鎖鎖定,故同個事務多次當前讀結果記錄數都是一致的,不存在幻讀情況。   測試3:快照讀測試 測試結果:同個事務多次讀取相同記錄,不存在髒讀及丟失更新、不可重複讀及幻讀等情況。 總結:支援快照讀,快照讀跟當前讀不存在髒讀、不可重複讀問題、幻讀問題。  

5.2.4 Read Serializable

所有事務隔離級別設定: set session transaction isolation level Serializable   ; 該隔離級別不支援快照讀,所有SELECT查詢都是當前讀,並且持有S鎖. 測試1:update資料不提交,另起查詢;INSERT資料不提交,另起事務多次查詢 測試結果:該隔離級別下所有select語句持有S鎖,導致update申請X鎖處於等待情況,INSERT申請X也被堵塞,同個事務內的多次查詢結果一致,不存在髒讀、不可重複讀及幻讀情況。   總結:無快照讀,所有SELECT查詢都是當前讀,不存在髒讀、不可重複讀問題、幻讀問題。 以為沒了,not,還有一個概念這裡沒有提交,這裡補充介紹下:semi-consistent read

PS: semi-consistent read

在read committed或者read uncommitted 隔離級別下,有這樣的測試現象: 測試表格及資料 CREATE TABLE `tblock` (   `id` int(11) NOT NULL AUTO_INCREMENT,   `name` varchar(10) DEFAULT NULL,   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; insert into tblock(name) select 'su'; insert into tblock(name) select 'xin'; 測試1:兩個update事務併發,分別update不同行,update條件列無索引 測試結果:兩條update互不干擾,正常執行。 測試2:update語句不提交,另起事務當前讀操作 測試結果:當前讀被堵塞,無法正常加X鎖     問題點:為啥兩個測試中的sql序號2,都是申請X鎖,測試1可以正常申請情況,而測試2不行呢?     正常情況下,where條件中的name列沒有索引,故這個update操作是對全表做scan掃描加X鎖,正常情況下,在第一個事務中,update語句沒有提交的情況下,這個表格有一個表鎖X,對每一行資料都無法申請S鎖或者X鎖,那麼為什麼 測試1 可以正常申請呢?     在這裡,需要引入semi-constent-read,半一致性讀。官網解釋如下: semi consistent read: A type of read operation used for UPDATE statements, that is a combination of read committed and consistent read. When an UPDATE statement examines a row that is already locked, InnoDB returns the latest committed version to MySQL so that MySQL can determine whether the row matches the WHERE condition of the UPDATE. If the row matches (must be updated), MySQL reads the row again, and this time InnoDB either locks it or waits for a lock on it. This type of read operation can only happen when the transaction has the read committed isolation level, or when the innodb_locks_unsafe_for_binlog option is enabled.    semi-consistent read是update語句在讀資料的一種操作, 是read committed與consistent read兩者的結合。update語句A在沒有提交時,另外一個update語句B讀到一行已經被A加鎖的記錄,但是這行記錄不在A的where條件內,此時InnoDB返回記錄最近提交的版本給B,由MySQL上層判斷此版本是否滿足B的update的where條件。若滿足(需要更新),則MySQL會重新發起一次讀操作,此時會讀取行的最新版本(並加鎖)。semi-consistent read只會發生在read committed及read uncommitted隔離級別,或者是引數innodb_locks_unsafe_for_binlog被設定為true。 對update起作用,對select insert delete 不起作用。這就導致了update 不堵塞,但是當前讀的select則被堵塞的現象。    發生 semi consitent read的條件:
  1. update語句
  2. 執行計劃時scan,range scan or table scan,不能時unique scan
  3. 表格為聚集索引
總結如下:  

相關推薦

mysql併發處理機制_

    回來寫部落格,少年前端時間被django迷了心魄 1 什麼是MVCC        MVCC全稱是: Multiversion concurrency control,多版本併發控制,提供併發訪問資料庫時,對事務內讀取的到的記憶體做處理,用來避免寫操作堵塞讀操作的併發

mysql併發處理機制_下篇

    溫馨提示:下文有幾個表格長度較長,右下角的博文導航目錄會擋道,瀏覽時,可以點選 導航目錄的左下角按鈕收縮目錄:  1 Innodb的鎖     在innodb中,有4種類型的鎖:IX、X、IS及S鎖,其說明如下: 型別 說明 場景 S

mysql併發處理機制

在innodb中,有4種類型的鎖:IX、X、IS及S鎖,其說明如下:      型別說明 場景      S共享鎖 針對於RS隔離級別的查詢或者新增Lock in share mode的SELECT查詢而產生的鎖      X排它鎖 針對於update、delete、ins

【MyBatis源碼分析】insert方法、update方法、delete方法處理流程(

times database connect 環境 enable clas 它的 java對象 ace 打開一個會話Session 前文分析了MyBatis將配置文件轉換為Java對象的流程,本文開始分析一下insert方法、update方法、delete方法處理的流程,至

【ASP.NET Core】處理異常(

關心 指向 然而 sub 相關 pri roo epon netcore 依照老周的良好作風,開始之前先說點題外話。 前面的博文中,老周介紹過自定義 MVC 視圖的搜索路徑,即向 ViewLocationFormats 列表添加相應的內容,其實,對 Razor Page

深入理解Java異常處理機制 (籠統

throw 種類型 綜合 IV 算術 其它 wid all 作用 開篇 1.異常處理(Exception Handling):   就是一種解決這一問題的機制,能夠較好地處理程序不能正常運行的情況。 2.異常(Exception):   是程序在運行時可能出現的

Mysql心路歷程:Mysql各種鎖機制(進階)

通過上一篇基本鎖的介紹,基本上Mysql的基礎加鎖步奏,有了一個大概的瞭解。接下來我們進入最後一個鎖的議題:間隙鎖。間隙鎖,與行

SQL Server與MySQL在“存在則更新,不存在則插入”併發處理的一些差異。

“存在則更新,不存在則插入的邏輯”併發情況下的處理 在sqlserver中: 在sqlserver中,是通過可序列化隔離級別+排它鎖的方式來鎖定一個範圍來實現的當前鎖定一個不存在的記錄的時候,sqlserver是通過範圍鎖來實現的,具體鎖定的範圍,表中已存在的資料和當前具體判斷的Id有關參考之前寫的一

【朝花夕拾】Android自定義View之(五)Android事件分發機制)三個重要方法的處理邏輯

前言        在自定義View中,經常需要處理Android事件分發的問題,尤其在有多個輸入裝置(如遙控、滑鼠、遊戲手柄等)時,事件處理問題尤為突出。Android事件分發機制,一直以來都是一個讓眾多開發者困擾的難點,至少筆者在工作的前幾年中,沒有特意研究它之前

Mysql的鎖機制與PHP文件鎖處理高並發簡單思路

三種 default [0 pda utf8 pen sql incr update 以購買商品舉例: ① 從數據庫獲取庫存的數量。 ② 檢查一下庫存的數量是否充足。 ③ 庫存的數量減去買家購買的數量(以每個用戶購買一個為例)。 ④ 最後完成購買。 僅僅這幾行邏輯代碼在並發

Android 異步消息處理機制(二):深入理解Message消息池

連接 guid ply 指針 cau ann 區別 就會 消息處理機制 版權聲明:本文出自汪磊的博客,轉載請務必註明出處。 上一篇中共同探討了ThreadLocal,這篇我們一起看下常提到的Message消息池到底是怎麽回事,廢話少說吧,進入正題。 對於稍有經驗的開發人員來

Linux學習總結(四十五)mysql 基本操作

msyql1. 首次登入數據庫 /usr/local/mysql/bin/mysql -uroot我們發現直接登入了,不需要驗證。因為我們還沒有給root 用戶設置密碼,默認是沒有密碼的。如果不指定用戶,則默認是root用戶登陸。我們發現僅僅登陸一個數據庫,要輸入如此長的路徑,太辛苦了,我們可以把該路徑放進環

Python3實現ICMP遠控後門()_補充

eply image left adding TP 網絡 管理 如何實現 style ICMP後門(上)補充篇 前言 在上一篇文章Python3實現ICMP遠控後門(上)中,我簡要講解了ICMP協議,以及實現了一個簡單的ping功能,在文章發表之後,後臺很多朋友留言,

MySQL · 引擎特性 · B+樹併發控制機制的前世今生

前言 B+樹是1970年Rudolf Bayer教授在《Organization and Maintenance of Large Ordered Indices》一文中提出的[1]。它採用多叉樹結構,降低了索引結構的深度,避免傳統二叉樹結構中絕大部分的隨機訪問操作,從而有效減少了磁碟磁頭的尋道

MySQL多版本併發控制機制(MVCC)-原始碼淺析

前言 作為一個數據庫愛好者,自己動手寫過簡單的SQL解析器以及儲存引擎,但感覺還是不夠過癮。<<事務處理-概念與技術>>誠然講的非常透徹,但只能提綱挈領,不能讓你玩轉某個真正的資料庫。感謝cmake,能夠讓我在mac上用xcode去debug MySQL,從而能去領略它的

Python3 與 C# 併發程式設計之~ 執行緒

2.2.加強篇¶ 其實以前的Linux中是沒有執行緒這個概念的,Windows程式設計師經常使用執行緒,這一看~方便啊,然後可能是當時程式設計師偷懶了,就把程序模組改了改(這就是為什麼之前說Linux下的多程序程式設計其實沒有Win下那麼“重量級”),弄了個精簡版程序==>執行緒(核心是分不出程序

【搞定Java併發程式設計】第3:多執行緒概述~

上一篇:併發基礎概述:https://blog.csdn.net/pcwl1206/article/details/84833911 目  錄: 1、什麼是執行緒 2、執行緒的建立 2.1、Thread和Runnable簡介 2.2、Thread和Runnable的異同

文章對於瞭解Javascript的事件處理機制非常好,將它全文轉載於此,以備不時之需。

什麼是事件? 事件(Event)是JavaScript應用跳動的心臟 ,也是把所有東西粘在一起的膠水。當我們與瀏覽器中 Web 頁面進行某些型別的互動時,事件就發生了。事件可能是使用者在某些內容上的點選、滑鼠經過某個特定元素或按下鍵盤上的某些按鍵。事件還可能是 Web

從零開始學習比特幣--P2P 網路的建立之訊息處理

現在終於,來到了我們非常非常關心比特幣訊息處理,通過比特幣訊息處理,我們會理解比特幣的協義,理解比特幣是如何同步區塊,如何傳送交易,從而建立起理解比特幣的至關重要一步。 本部分內容是如此的重要,也是相當的長,所以我們分上下兩部分來介紹具體的訊息處理。 上篇主要

Linuxmysql錯誤處理之ERROR 1786 (HY000)

1.錯誤描述 在資料庫中執行語句:CREATE TABLE mis_auto_sagaw_sub_qiyexiaoshougepinzhobak131 SELECT * FROM mis_auto_sagaw_sub_qiyexiaoshougepinzho WHERE m