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 隔離級別說明
- Read UnCommitted
- 簡稱 RU,讀未提交記錄,始終是讀最新記錄
- 可能存在髒讀、不可重複讀、幻讀等問題
- 讀的過程不加S鎖,等同於 SELECT * FROM tbname with(nolock)
- 簡稱 RC ,讀已提交記錄
- 可能存在不可重複讀、幻讀等問題
- 讀的過程加 S鎖,無論事務是否結束,SELECT 語句一旦結束,立馬釋放S鎖,不會等到事務結束才釋放鎖,遵循的是 Strict 2-PL
- 簡稱 RCSI
- 應用MVCC原理,版本讀,讀已提交記錄,但是讀取到的不一定是最新的記錄
- 同個事務中,讀取資料都是同一個版本
- 不存在髒讀、不可重複讀問題,可能存在幻讀問題
- 行版本控制隔離級別 中的版本資料,不存在與資料庫本身,而是存在 tempdb ,下文會詳細描述這一隔離級別
- 簡稱 RR ,可重複讀記錄
- 可能存在幻讀等問題
- 讀的過程加S鎖,直到事務結束,才釋放S鎖,遵循的是 Stong Strict 2-PL
- 簡稱 SI
- 下文會詳細描述這一隔離級別
- 簡稱 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;
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) 原子性:保證事務包含的一組資料庫操作