1. 程式人生 > >MSSQL-併發控制-2-Isolation

MSSQL-併發控制-2-Isolation

       MySQL通過MVCC和鎖來實現併發控制,在4個隔離級別中,讀寫資料方式及加鎖方式有所不同,以滿足不同的業務需求。

    而在MSSQL中,也是通過鎖和MVCC的行版本來實現併發控制。     每個事務中,鎖的型別、級別、加鎖、釋放的情況,由事務的隔離級別控制,在MSSQL中,有6個隔離級別,不同的隔離級別對鎖的應用不一樣。而這兩個隔離級別中,有2個應用 MVCC的機制,也就是 快照類的隔離級別:Read Commmitted Snapshot 跟 Snapshot。

1 併發控制理論

    在MSSQL中,經常用到的併發控制理論是 悲觀併發控制跟樂觀併發控制。

1.1 悲觀併發控制

    悲觀併發,預設在事務操作過程中,一定會有其他事務跟它爭奪資源,所以在事務操作過程中,會根據不同的情況對資料新增鎖,避免操作期間其他事務對該資料的修改或讀取,保證資料的一致性。     悲觀併發控制,由於納入了鎖機制,很大程度會影響到併發規模。主要應用於資料頻繁修改、並且回滾事務的成本要大於鎖資料的成本 的系統中

1.2 樂觀併發控制

    樂觀控制,預設事務在讀取資料的時候,其他事務並沒有在操作這些資料,所以不會加鎖,直接修改資料,修改後檢視讀取資料期間是否有其他使用者也修改了資料,如果有,則回滾本身的修改事務。     樂觀併發控制,應用於資料修改不頻繁、並且 回滾事務成本要小於鎖資料成本 的系統中
 

2 隔離級別

    在每一個事務中,都指定了一個隔離級別,該隔離級別定義了這個事務跟其他事務之間的隔離程度。     在MSSQL中,有6種隔離級別,4個常規隔離級別跟2個快照隔離級別:Read UnCommitted、Read Committed、Read Commmitted (行版本)、Read Repeattable、Snapshot跟Read Serializeble。Read Commmitted (行版本)跟Snapshot 可能接觸情況比較少,不過仍會說明。     在MySQL中,預設的隔離級別是RR,而在SQL SERVER中,預設的隔離級別是RC,讀已提交。

2.1 隔離級別說明

    如何設定整個資料庫的預設隔離級別?     下文中說S鎖,並不是全部加鎖過程(MSSQL中還是IS鎖的申請)。
  1. Read UnCommitted
  • 簡稱 RU,讀未提交記錄,始終是讀最新記錄
  • 可能存在髒讀、不可重複讀、幻讀等問題
  • 讀的過程不加S鎖,等同於 SELECT * FROM tbname with(nolock)
  • Read Committed
    • 簡稱 RC ,讀已提交記錄
    • 可能存在不可重複讀、幻讀等問題
    • 讀的過程加 S鎖,無論事務是否結束,SELECT 語句一旦結束,立馬釋放S鎖,不會等到事務結束才釋放鎖,遵循的是 Strict 2-PL
  • Read Commmitted (行版本)
    • 簡稱 RCSI
    • 應用MVCC原理,版本讀,讀已提交記錄,但是讀取到的不一定是最新的記錄
    • 同個事務中,讀取資料都是同一個版本
    • 不存在髒讀、不可重複讀問題,可能存在幻讀問題
    • 行版本控制隔離級別 中的版本資料,不存在與資料庫本身,而是存在 tempdb ,下文會詳細描述這一隔離級別
  • Read Repeattable
    • 簡稱 RR ,可重複讀記錄
    • 可能存在幻讀等問題
    • 讀的過程加S鎖,直到事務結束,才釋放S鎖,遵循的是 Stong Strict 2-PL
  • Snapshot
    • 簡稱 SI
    • 下文會詳細描述這一隔離級別
  • Read Serializeble
    • 簡稱 RS,序列化讀記錄
    • 不存在 髒讀、不可重複讀、幻讀等問題
    • 讀的過程中除了新增S鎖,還新增範圍鎖;修改資料的過程中,除了新增 X 鎖,也會新增範圍鎖,避免在符合條件的資料在操作過程中,有其他符合條件的資料INSERT進來
    • 併發度最差,除非明確業務需求及效能影響才使用,曾經遇到過某個簡訊業務的框架預設使用這個隔離級別,上線後爆發死鎖上K個,馬上分析緊急修復....

    2.2 Read Commmitted Snapshot Isolation 與 Snapshot Isolation

        Read Commmitted Snapshot Isolation 使用行版本控制語句級的快照,在事務中當資料發生修改或者刪除時,呼叫寫入複製機制,保證寫入的行資料的舊版本滿足事務操作前的一致性。 RCSI 保證的是語句級的 讀一致性。     Snapshot Isolation 使用行版本控制事務級的快照,當事務開始的時候,呼叫寫入複製機制。 SI 保證的是事務級 的讀取一致性。      如何管理行版本資訊呢?      兩者的行版本的資訊均儲存在tempdb資料庫內,並非儲存在本身的資料庫,這就要求tempdb要有足夠的空間儲存版本資訊,如果tempdb空間不足,則行版本寫入失敗,造成該隔離級別無法正常使用。      儲存引擎對使用 RCSI 或者 SI 隔離級別的事務,在 SI事務開始的時候,分配一個事務序列號 XLN,每次分配遞增1,以此實現事務級的一致性,這裡注意 RCSI的 事務序列號 並不是一個事務一個序列號,而是事務內每條SQL一個事務序列號,以此來實現語句級別的快照。這兩個隔離級別下,需要維護所有執行過資料修改的邏輯副本(即行版本),這些邏輯副本儲存在tempdb內,每個邏輯副本(行版本)都有標記本次的事務的事務序列號XLN。即 最新的行值儲存在當前的資料庫中,而歷史行版本資訊包括最新版本,儲存在tempdb中。這裡注意一下,事務內的修改資料寫行版本資訊的時候,先寫入到快取池中,在重新整理到tempdb檔案,避免效能造成太大的影響。     這個時候,可能會問?那豈不是tempdb要儲存非常多的歷史版本資料,有沒有刪除機制呢?     這個是有的,一方面,行版本資訊不會即時刪除,因為要保證基於行版本控制隔離級別下執行的事務要求,保證並行的事務如果正在使用tempdb的行版本資訊 不會受到影響。另一方面,資料庫的儲存引擎 會跟蹤最早可用的事務序列號,然後定期刪除比序列號更小的 XLN的所有行版本。       如何讀取行版本資訊呢?       兩個快照隔離級別下的 的事務讀資料的時候,不會獲取正在讀取資料上的共享鎖,因此不會堵塞正在修改的事務,由於減少了鎖的申請及數量,可以提供其DB併發能力。不過會獲取所在表格的架構鎖,如果表格正在發現架構修改(如列增加修改等),則會被堵塞。       如何讀取合適的行版本,RCSI 跟 SI 之間是有區別的。       RCSI:每次啟動語句時,提交所有資料,同時讀取tempdb中的最新事務序列,這使 RCSI 下事務內的每個語句 都可以檢視每個語句啟動時存在的最新資料的快照,也就是 事務內多個SQL查詢間隙中有其他事務修改了資料,那麼同個事務的多次相同SQL查詢結果就會出現不一致的情況。       SI:每次啟動事務時,提交所有資料,讀取 最接近但低於 本身的 快照事務序列號,也就是 事務內的多個SQL 查詢,讀到的資料都是同一個版本,即使多次查詢間隙有其他事務修改資料,讀到的結果也是一致的。       如何修改行版本資訊呢 ?       在使用 RCSI 事務中,使用阻塞性掃描(其中讀取資料值時將在資料行上採用更新鎖(U 鎖)完成選擇要更新的行,滿足條件的行記錄將升級更新鎖到排它鎖,注意,這裡掃描的不是tempdb裡邊的行版本資訊,而是實際資料庫裡邊的最新行記錄,修改資料的機制跟 RC 相同。 如果資料行不符合更新條件,則在該行上將釋放更新鎖,同時鎖定下一行並對其進行掃描。持有鎖之後,則進行資料更新,事務結束後,釋放鎖。       在使用 SI 事務中,對資料修改採用樂觀方法:使用行版本的資料,進行資料修改,直到資料修改完成是,才獲取實際資料上的鎖, 當資料行符合更新標準時,則提交修改的資料行。 如果資料行已在快照事務以外修改,則將出現更新衝突,同時快照事務也將終止。 更新衝突由資料庫引擎處理,無法禁用更新衝突檢測。       從簡單的SQL來分析,WHERE條件均為主鍵(僅為個人測試推測):
    • 同個事務,多次 SELECT  * FROM tbname WHERE id=2
      • RCSI,在同個事務中,每個SQL啟動的時候,提交資料到tempdb表格(個人推測,應該是會分配一個類似hash字串之類的,如果同個事務中的多次查詢結果一致,應該不用在每個SQL開始的時候,重複提交行版本到tempdb),從tempdb中讀取最新版本資訊,如果tempdb沒有版本資訊,則從 資料庫中讀取,並把讀取到的記錄儲存在 tempdb。會存在同個事務中,多次讀取資料結果不一致的情況。
      • SI,在同個事務中,同個事務內的相同SQL 從tempdb中讀取距離當前事務最新的版本,整個事務內部的SQL都是用這個版本資料,如果tempdb沒有版本資訊,則從 資料庫中讀取,並把讀取到的記錄儲存在 tempdb。同個事務中,不會存在 多次讀取資料結果不一致的情況。
    • UPDATE tbname SET colname='xinysu' WHERE id=18
      • RCSI,直接讀取資料庫中的資料,根據主鍵加上X鎖,更新資料,這個操作跟 RC 隔離級別是一樣的。
      • SI,讀取 行版本 資料,在行版本上選擇需要更新的行,修改成功後把資料 修改到實際的資料庫中去,如果 實際資料庫中的資料在這段操作期間已被其他事務修改了數值,則會出現更新衝突,該事務將報錯停止。即,SI 在 UPDATE 的時候,有更新衝突檢測。
        • 為啥要先在行版本上更新,最後在更新到實際資料上?
        • 假設一個UPDATE執行需要3s,但是隻更新了1條行記錄,如果直接在實際資料上更新,則需要鎖定掃描記錄3s,最後更新,中間會堵塞到其他事務對該資料的查詢,但是如果在行版本上更新,則不需要鎖住 實際資料,最後更新1行記錄的時候,非常快,避免長時間的堵塞,提高併發能力
    屬性 使用行版本控制的已提交讀隔離級別 快照隔離級別
    資料庫級選項啟動  READ_COMMITTED_SNAPSHOT ALLOW_SNAPSHOT_ISOLATION
    事務設定 使用預設的已提交讀隔離級別,或執行 SET TRANSACTION ISOLATION LEVEL 語句來指定 READ COMMITTED 隔離級別  SET TRANSACTION ISOLATION LEVEL 來在事務啟動前指定 SNAPSHOT 隔離級別
    行版本處理 在每條語句啟動前提交的所有資料。 在每個事務啟動前提交的所有資料。
    更新處理 從行版本恢復到實際的資料,以選擇要更新的行並使用選擇的資料行上的更新鎖。 獲取要修改的實際資料行上的排他鎖。 沒有更新衝突檢測。 使用行版本選擇要更新的行。 嘗試獲取要修改的實際資料行上的排他鎖,如果資料已被其他事務修改,則出現更新衝突,同時快照事務也將終止。
    更新衝突檢測 整合支援。 無法禁用。

    3 隔離級別測試

        檢視當前會話的資料庫隔離級別:DBCC USEROPTIONS ,檢視[set options] = 'isolation level',即可檢視當前事務的隔離級別。     設定資料庫隔離級別:
    • RU,事務開始的時候,設定 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    • RC,事務開始的時候,設定 SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    • RCSI,整個資料庫級設定 READ_COMMITTED_SNAPSHOT 為ON,注意,設定的這個的時候需要獲取資料庫的獨佔權,也就是當前不允許有使用者執行緒連線資料庫,否者這個設定SQL會一直處於堵塞情況。如果當前資料庫的預設隔離級別是 RC,則設定後,預設為RCSI,否者,需要在事務開始的時候,設定 SET TRANSACTION ISOLATION LEVEL READ COMMITTED
      • 資料庫設定:當前資料庫下,執行 ALTER DATABASE dbname SET READ_COMMITTED_SNAPSHOT ON
      • 事務設定:SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    • RR,事務開始的時候,設定 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
    • RS,事務開始的時候,設定 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    • SI,整個資料庫級設定 ALLOW_SNAPSHOT_ISOLATION 為ON,同時設定事務的隔離級別為 SNAPSHOT。注意,這裡的 ALLOW_SNAPSHOT_ISOLATION 設定也是需要獲取資料的獨佔鎖。
      • 資料庫設定:當前資料庫下,執行 ALTER DATABASE dbname SET ALLOW_SNAPSHOT_ISOLATION ON
      • 事務設定:SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
        測試過程中,分為3個表格:無索引、有索引、有唯一索引。  
    CREATE TABLE tb_no_index ( id int primary key not null identity(1,1), age int not null, name varchar(100) );
    CREATE TABLE tb_index ( id int primary key not null identity(1,1), age int not null, name varchar(100) );
    CREATE TABLE tb_unique_index ( id int primary key not null identity(1,1), age int not null,name varchar(100) );
     
    CREATE INDEX IX_age ON tb_index(age)
    CREATE INDEX IX_unique_age ON tb_index(age)
     
    INSERT INTO tb_no_index(age) values(2),(9),(21),(4),(7),(25);
    INSERT INTO tb_index(age) values(2),(9),(21),(4),(7),(25);
    INSERT INTO tb_unique_index(age) values(2),(9),(21),(4),(7),(25);

    3.1 Read Uncommitted

    • 資料不一致情況測試截圖 
    • RU測試結論
      • 在RU隔離級別下
        • 不會出現更新丟失情況(鎖機制),但是會出現 髒讀、不可重複讀及幻讀的情況。
        • 讀不加行鎖,可以讀未提交資料

    3.2 Read Committed

    • 資料不一致情況測試截圖
    • 讀情況測試
    • RC測試結論
      • 在RC隔離級別下
        • 不會出現更新丟失情況(鎖機制)、髒讀現象,但是會出現 不可重複讀及幻讀的情況
        • 讀需要申請鎖,故不會出現髒讀情況
        • 遵循 強2-PL模式,事務內的讀鎖讀完即刻釋放,寫鎖等到事務提交的時候才釋放。

    3.3 Read Commit Snapshot Isolation

    • 測試環境設定
      • 實現設定資料庫隔離級別為:
      • 檢查當前會話的預設隔離級別:
    • 資料不一致情況測試截圖
    • 更新衝突測試
    • RCSI 測試結論
      • 讀不加鎖,但申請表格的架構鎖,讀行版本資料
      • 不存在丟失更新、髒讀情況,但是存在不可重複讀及幻讀情況
      • 沒有更新衝突檢測,RCSI跟RC的更新處理方式一樣

    3.4 Read Reaptable

    • 資料不一致情況測試截圖
    • RR測試結論
      • 讀加S鎖,事務結束後才釋放S鎖
      • 不存在丟失更新、髒讀及不可重複讀情況,但是存在幻讀情況

    3.5 Read Serializable

    • 資料不一致情況測試截圖
    • RS 測試結論
      • 讀加S鎖,事務結束後才釋放S鎖
      • 增加了範圍鎖
      • 不存在丟失更新、髒讀、不可重複讀、幻讀情況
      • 併發能力最差

    3.6 Snapshot Isolation

    • 資料不一致情況測試截圖
    • 更新衝突測試
    • SI 測試結論
      • 不存在 丟失更新、髒讀、幻讀等資料不一致情況
      • 讀不加鎖,為讀行版本資料
      • 具有衝突監測,無法禁用,如果使用這個隔離級別,程式要做更新衝突的回滾處理

    4 總結

    隔離級別 說明 髒讀 不可重複讀 幻影 併發控制模型
    Read UnCommitted 未提交讀 YES YES YES 悲觀
    Read Committed 已提交讀 NO YES YES 悲觀
    Read Commmitted (行版本) 已提交讀(快照) NO YES YES 樂觀
    Read Repeattable 可重複讀 NO NO YES 悲觀
    Snapshot 快照 NO NO NO 樂觀
    Read Serializeble 可序列化 NO NO NO 悲觀

    相關推薦

    MSSQL-併發控制-2-Isolation

           MySQL通過MVCC和鎖來實現併發控制,在4個隔離級別中,讀寫資料方式及加鎖方式有所不同,以滿足不同的業務需求。     而在MSSQL中,也是通過鎖和MVCC的行版本來實現併發控制。     每個事務中,鎖的型別

    MSSQL-並發控制-2-Isolation

    ora eat 在操作 -c ransac class 線程 .html 跟蹤 如果轉載,請註明博文來源: www.cnblogs.com/xinysu/ ,版權歸 博客園 蘇家小蘿蔔 所有。望各位支持!

    MSSQL-併發控制-1-Transaction

       MSSQL併發控制原先打算分為兩個部分寫:隔離級別及鎖,寫的過程中,發現需要提及下事務的相關內容,故加多一篇博文,共3篇。    併發控制,在於控制每一個事務的操作過程以及它們對資源的佔用情況,同時要保證事務的ACID特性。這裡簡單描述事務類別、ACID特性及對分散式事務的簡要說明。

    1.2 併發控制

    無論何時,只要有多個查詢需要在同一時刻修改資料,就會產生併發控制的問題。 MySQL提供鎖來防止資料損壞,但是這種方案並不支援併發處理。 1.2.1 讀寫鎖    共享鎖(Shared),簡寫為 S 鎖,又稱讀鎖。是共享的,或者說是相互不阻塞的。多個客戶在同一時刻可以同時讀取同一個資源,而互不干擾。

    MSSQL WAF繞過(2)

    serve 通過 需要 process term image nag 頁面 一次 0x00 前言 上次的繞過太簡單,也沒有能註出數據或者獲取權限,這次繼續繞過,獲取數據 0x01 過程 還是上次的站點,簡單的判斷,存在註入 發現and 數字、exec、union sel

    (二)上交無人機比賽 基本控制-2控制添加

    spa IV time mov period () static RM second 已有的為功能 namespace msr { namespace airlib { typedef msr::airlib_rpclib::MultirotorRpcL

    Java併發控制:ReentrantLock Condition的使用

    生產者-消費者(producer-consumer)問題,也稱作有界緩衝區(bounded-buffer)問題,兩個程序共享一個公共的固定大小的緩衝區。 其中一個是生產者,用於將訊息放入緩衝區;另外一個是消費者,用於從緩衝區中取出訊息。 問題出現在當緩衝區已經滿了,而此時生產者還想

    ES:partial update 原理、 基於groovy使用、 內建樂觀鎖併發控制

    1、partial update基本語法 POST /index/type/id/_update { "doc" : { "要修改的少數幾個field即可,不需要全量的資料" } } 每次就傳遞少數幾個發生修改的field即可,不需要將全量的docu

    ES:基於_version進行樂觀鎖併發控制

    圖示的衝突過程,其實就是es的併發衝突問題,會導致資料不準確 當併發操作es的執行緒越多,或者讀取一份資料,供使用者查詢和操作的時間越長,在這段時間裡,如果資料被其他使用者修改,那麼我們拿到的就是舊資料,基於舊資料去操作,就會導致錯誤的結果 1、悲觀鎖與樂觀鎖兩種併發

    Java併發程式設計(2)-共享物件解讀

    文章目錄 一、變數可見性 1.1、共享物件的可見性 1.2 、volatile變數 二、變數釋出與逸出 2.1、如何釋出物件 2.2、釋出物件帶來的t

    ElasticSearch最佳入門實踐(二十四)partial update樂觀鎖併發控制原理以及相關操作

    (1)partial update內建樂觀鎖併發控制 partial update內部是自動執行之前所說的樂觀鎖的併發控制方案 兩個執行緒 都拿到了document資料和_version 使用傳過來的field更新document 執行緒B也在做partial update

    【轉】【MySQL】MySQL的併發控制與加鎖分析

    https://www.cnblogs.com/yelbosh/p/5813865.html  本文主要是針對MySQL/InnoDB的併發控制和加鎖技術做一個比較深入的剖析,並且對其中涉及到的重要的概念,如多版本併發控制(MVCC),髒讀(dirty read),幻讀(phantom read

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

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

    Java嚴格控制2個執行緒的交替執行次數

    以下程式碼可以實現兩個執行緒(A和B)任意次數的交替執行,比如,A執行緒執行m次,B執行緒執行n次,A執行緒又執行m次,B執行緒又執行n次…如此交替迴圈。 首先定義一個鎖類,該類的作用是充當執行緒之間的通訊角色,並定義各個執行緒的執行次數,同時還包含了執行緒的主體執行方法,程式碼如下:

    OGL(教程15)——攝像機控制2

    原文地址:http://ogldev.atspace.co.uk/www/tutorial15/tutorial15.html 背景知識: 本節我們將會完成實現滑鼠控制攝像機方向。在涉及攝像機的時候有很多不能層級的自由性。我們將以第一視角遊戲的方式控制相機。這就意味著我們能夠改變攝像機的

    elasticsearch 筆記七: es樂觀鎖的併發控制

    1.併發控制 es 的併發控制是通過多version來實現的(不清楚樂觀鎖的自己提升去) 2.例項 //建立索引 PUT /test_index/test_type/7 { "test_field": "test test" } //返回建立結果 GET test_index

    [pg]資料庫的併發控制

    參考 章 13. 併發控制 資料庫併發事務控制四:postgresql資料庫的鎖機制二:表鎖 PostgreSQL 事務處理和併發控制 PostgreSQL併發控制(MVCC, 事務,事務隔離級別) 資料庫中Select For update語句的解析 Postgre

    Java線上併發控制word文件

    前言: 對於線上操作word文件的OA系統來說有一個常見問題,就是對於服務端放置的word文件,如果有兩個人甚至更多客戶端同時開啟該文件時,就會存在併發問題。有了併發問題就會出現操作的文件儲存內容被覆蓋的問題,造成使用者編輯資料丟失,這是很致命的,該如何解決呢? 首先我們可以通過系統業務邏輯來限

    Kubernetes併發控制與資料一致性的實現原理

    在大型分散式系統中,定會存在大量併發寫入的場景。在這種場景下如何進行更好的併發控制,即在多個任務同時存取資料時保證資料的一致性,成為分散式系統必須解決的問題。悲觀併發控制和樂觀併發控制是併發控制中採用的主要技術手段,對於不同的業務場景,應該選擇不同的控制方法。悲觀鎖悲觀併發控制(又名“悲觀鎖”,Pessimi

    易學筆記-系統分析師考試-第5章 資料庫系統/5.4 資料庫控制功能/5.4.1併發控制

    併發控制 概念:多個事務對同一個資料來源的操作稱為併發 事務 概念:是DBMS執行的最基本工作單位,使用者定義的一個數據庫操作序列,這些操作序列要麼不做,要麼全部做 特徵(ACID) 原子性:保證事務包含的一組資料庫操作