LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

SQL Server 中的并發(fā)問題

admin
2024年12月23日 13:20 本文熱度 286

在現(xiàn)代數(shù)據(jù)庫應(yīng)用程序中,并發(fā)是不可避免的,因為多個用戶或多個應(yīng)用程序?qū)嵗龝瑫r訪問和更新相同的數(shù)據(jù)。高效地處理并發(fā)是數(shù)據(jù)庫管理系統(tǒng)(DBMS)必須面對的核心挑戰(zhàn)之一。若處理不當,將可能導致數(shù)據(jù)不一致或無法滿足性能需求。本文將詳細討論 SQL Server 中的并發(fā)、常見的并發(fā)問題,以及 SQL Server 提供的事務(wù)隔離級別來平衡性能與數(shù)據(jù)一致性。


什么是并發(fā)

并發(fā)是指多個事務(wù)(Transaction)或操作同時訪問或修改相同的數(shù)據(jù)。數(shù)據(jù)庫需要通過鎖(Lock)、事務(wù)隔離級別(Isolation Level)等機制,盡量減少并發(fā)沖突并確保數(shù)據(jù)一致性。

舉個簡單的例子:

  • 用戶 A 和用戶 B 同時查看并更新同一個客戶表中的同一行數(shù)據(jù)。若這兩個更新發(fā)生沖突,可能會導致不一致的數(shù)據(jù)寫回數(shù)據(jù)庫。

為了避免此類沖突或保證沖突可控,需要了解 SQL Server 提供的多種隔離級別以及具體的并發(fā)問題類型。


常見的并發(fā)問題

當兩個或更多事務(wù)對同一行或同一數(shù)據(jù)集進行讀寫時,就可能出現(xiàn)以下幾種并發(fā)問題:

  1. 丟失更新(Lost Update)

    • 當兩個事務(wù)讀取到相同的記錄并先后修改該記錄時,最后一個提交的事務(wù)覆蓋了前一個事務(wù)提交的結(jié)果,導致前一個事務(wù)的更新內(nèi)容被“丟失”。

    • 場景示例:

      1) 事務(wù) A 讀取某產(chǎn)品價格為 100 元,并打算減價 10 元。

      2) 事務(wù) B 幾乎同一時間也讀取該產(chǎn)品價格為 100 元,并打算減價 5 元。

      3) 事務(wù) A 將更新后的價格(90 元)寫回并提交。

      4) 事務(wù) B 將更新后的價格(95 元)寫回并提交,把 A 的減價覆蓋掉,導致 A 的更新丟失。

  2. 臟讀(Dirty Read)

    • 當一個事務(wù)讀取到另一個事務(wù)尚未提交(或已經(jīng)回滾)的數(shù)據(jù)時,就會產(chǎn)生臟讀。

    • 若該事務(wù)最終回滾,則第一個事務(wù)讀到的那條“更新”實際上從未正式存在過,導致數(shù)據(jù)可能出現(xiàn)不一致。

    • 場景示例:

      1) 事務(wù) A 更新某客戶的信用額度為 10000 元,但尚未提交。

      2) 此時事務(wù) B 讀取該客戶信用額度并發(fā)現(xiàn)是 10000 元,基于這個信息進行后續(xù)邏輯。

      3) 如果事務(wù) A 最后回滾,信用額度繼續(xù)保持原有值 5000 元。B 相當于用了一條 “不存在的更新” 做決策。

  3. 不可重復讀(Non-Repeatable Read)

    • 在同一事務(wù)中,兩次讀取同一行時,若中間有別的事務(wù)更新了該行,就會出現(xiàn)前后讀取數(shù)據(jù)不一致的情況,即“同一個查詢在同一事務(wù)里,前后兩次讀取結(jié)果不一致”。

    • 場景示例:

      1) 事務(wù) A 兩次讀取同一個客戶的地址信息。

      2) 在 A 的兩次讀取之間,事務(wù) B 修改了該地址信息。

      3) 事務(wù) A 第一次讀到的是“北京市朝陽區(qū)”,第二次讀到的是“上海市浦東新區(qū)”,產(chǎn)生不可重復讀。

  4. 幻讀(Phantom Read)

    • 指在同一事務(wù)里,一次查詢和下一次“同樣的查詢”獲取到的結(jié)果集行數(shù)不一致,因為中間可能有其他事務(wù)插入或刪除符合查詢條件的新數(shù)據(jù)行,導致事務(wù)產(chǎn)生“幻覺”——仿佛多了一行或少了一行數(shù)據(jù)。

    • 場景示例:

      1) 事務(wù) A 使用 SELECT * FROM Orders WHERE Amount > 1000 讀取符合金額大于 1000 的訂單列表。

      2) 在事務(wù) A 二次執(zhí)行相同查詢之前,事務(wù) B 插入了一條新訂單,金額也大于 1000。

      3) 事務(wù) A 再次執(zhí)行相同的查詢時,就會“發(fā)現(xiàn)”一條新行,好像出現(xiàn)了“幻影”數(shù)據(jù)。


事務(wù)隔離級別

為了應(yīng)對上述并發(fā)問題,SQL Server 提供了多種隔離級別(Isolation Level),它們在性能與數(shù)據(jù)一致性之間做出了不同程度的權(quán)衡。常用的事務(wù)隔離級別包括:

  1. 未提交讀(READ UNCOMMITTED)

    • 允許臟讀,不會對讀取操作加任何鎖,性能最高,數(shù)據(jù)一致性最弱。

    • 可能出現(xiàn)所有異常:臟讀、不可重復讀、幻讀和丟失更新。

  2. 已提交讀(READ COMMITTED)(SQL Server 默認)

    • 防止臟讀,會在讀取時加共享鎖,在讀取完后立即釋放。

    • 無法防止不可重復讀、幻讀和丟失更新。

  3. 可重復讀(REPEATABLE READ)

    • 在事務(wù)開始后,對已讀取的數(shù)據(jù)行加鎖并持續(xù)到事務(wù)結(jié)束,防止其他事務(wù)修改這些數(shù)據(jù)行,從而避免不可重復讀和丟失更新。

    • 可能仍會出現(xiàn)幻讀(因為沒有對“范圍”加鎖,可能有新行被插入)。

  4. 可序列化(SERIALIZABLE)

    • 在可重復讀的基礎(chǔ)上,還對“查詢范圍”加鎖,以防止新數(shù)據(jù)插入或現(xiàn)有數(shù)據(jù)刪除,徹底防止幻讀。

    • 并發(fā)度最低,但保證最高的一致性。

  5. 快照(SNAPSHOT)

    • 在事務(wù)開始時,對數(shù)據(jù)庫進行一個一致性鏡像(版本),后續(xù)所有讀取操作基于這個版本,避免臟讀、不可重復讀和幻讀。

    • 通過行版本控制減少鎖爭用,往往可以在高并發(fā)時提供更好的性能和一致性。


如何選擇合適的隔離級別

事務(wù)隔離級別的選擇往往需要在“讀一致性需求”和“性能需求”之間做出平衡:

  • 如果對數(shù)據(jù)一致性要求極高(如財務(wù)系統(tǒng)),往往需要使用更嚴格的隔離級別(如 SERIALIZABLE 或 SNAPSHOT)。

  • 如果對讀性能要求很高、對一致性容忍度相對較寬(如統(tǒng)計報表類場景),則可在 READ COMMITTED 或 READ UNCOMMITTED 之間進行考慮。

  • SNAPSHOT 隔離級別在許多實際應(yīng)用中是一個較平衡的方案,既減少鎖爭用,又避免大部分并發(fā)問題。

下表簡要概括了常見隔離級別與會遇到的問題:

隔離級別臟讀不可重復讀幻讀丟失更新
READ UNCOMMITTED可能可能可能可能
READ COMMITTED (默認)可能可能可能
REPEATABLE READ可能
SERIALIZABLE
SNAPSHOT否(*)

說明:
在 SNAPSHOT 隔離級別下,通過行版本控制機制避免大多數(shù)并發(fā)沖突,但一些業(yè)務(wù)邏輯層面的“邏輯沖突”仍有可能發(fā)生,需要進一步使用樂觀并發(fā)控制或顯式鎖來處理。


示例:理解并發(fā)讀取、更新與回滾

假設(shè)我們有一個簡單的 Customer 表,包含以下字段:

CustomerIDCustomerCodeCustomerName
1Code_1張三
2Code_2李四
.........

測試數(shù)據(jù)

-- 1. 首先創(chuàng)建測試表  
CREATE TABLE Customer (  
    CustomerID INT PRIMARY KEY,  
    CustomerCode VARCHAR(10),  
    CustomerName VARCHAR(50)  
);  

-- 2. 插入測試數(shù)據(jù)  
INSERT INTO Customer VALUES (1'Code_1''張三');  
INSERT INTO Customer VALUES (2'Code_2''李四');  
-- 窗口 1 (事務(wù) 1):  
BEGIN TRANSACTION;  
    -- 先讀取初始值  
    SELECT CustomerCode FROM Customer WHERE CustomerID = 1;  
    -- 應(yīng)該顯示 Code_1  

    -- 第一次更新  
    UPDATE Customer   
    SET CustomerCode = 'Code_101'  
    WHERE CustomerID = 1;  

    -- 模擬長時間操作  
    WAITFOR DELAY '00:00:10';  

    -- 第二次更新  
    UPDATE Customer   
    SET CustomerCode = 'Code_1101'  
    WHERE CustomerID = 1;  

    -- 最后回滾所有操作  
    ROLLBACK TRANSACTION;  
    -- 或者 COMMIT TRANSACTION; 如果想要提交更改  
-- 窗口 2 (事務(wù) 2):  
-- 可以設(shè)置不同的隔離級別來觀察行為差異  

-- 使用 READ UNCOMMITTED (會看到未提交的更改)  
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;  
BEGIN TRANSACTION;  
    -- 第一次讀取  
    SELECT CustomerCode FROM Customer WHERE CustomerID = 1;  
    -- 等待幾秒后再次讀取  
    WAITFOR DELAY '00:00:05';  
    -- 第二次讀取  
    SELECT CustomerCode FROM Customer WHERE CustomerID = 1;  
    -- 再等待幾秒  
    WAITFOR DELAY '00:00:05';  
    -- 第三次讀取  
    SELECT CustomerCode FROM Customer WHERE CustomerID = 1;  
COMMIT TRANSACTION;  

-- 或者使用 READ COMMITTED (默認級別,只能看到已提交的更改)  
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;  
BEGIN TRANSACTION;  
    -- 重復上述查詢操作  
    SELECT CustomerCode FROM Customer WHERE CustomerID = 1;  
    WAITFOR DELAY '00:00:05';  
    SELECT CustomerCode FROM Customer WHERE CustomerID = 1;  
    WAITFOR DELAY '00:00:05';  
    SELECT CustomerCode FROM Customer WHERE CustomerID = 1;  
COMMIT TRANSACTION;  

-- 使用 SNAPSHOT 隔離級別前需要先啟用數(shù)據(jù)庫的SNAPSHOT功能  
ALTER DATABASE testdb  
SET ALLOW_SNAPSHOT_ISOLATION ON;  

-- 然后可以使用 SNAPSHOT 隔離級別  
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;  
BEGIN TRANSACTION;  
    -- 重復上述查詢操作  
    SELECT CustomerCode FROM Customer WHERE CustomerID = 1;  
    WAITFOR DELAY '00:00:05';  
    SELECT CustomerCode FROM Customer WHERE CustomerID = 1;  
    WAITFOR DELAY '00:00:05';  
    SELECT CustomerCode FROM Customer WHERE CustomerID = 1;  
COMMIT TRANSACTION;  

當兩個事務(wù)同時訪問 CustomerID = 1 的記錄時可能發(fā)生如下場景:

  1. 事務(wù) 1 先讀取到 CustomerCode = Code_1

  2. 事務(wù) 1 更新 CustomerCode 到 Code_101 并在此事務(wù)中保持鎖,執(zhí)行耗時約 10 秒。

  3. 事務(wù) 2 此時讀取到更新后的 Code_101(若在 READ COMMITTED 級別下,需要事務(wù) 1 提交后才可見,否則就需要 SNAPSHOT 或其他機制)。

  4. 事務(wù) 1 在 10 秒后再次更新 CustomerCode 為 Code_1101

  5. 事務(wù) 2 重新讀取數(shù)據(jù),得到了新的 Code_1101

  6. 事務(wù) 1 最后決定回滾(ROLLBACK),會將 CustomerCode 恢復到初始值 Code_1

  7. 事務(wù) 2 若再次讀取,就會發(fā)現(xiàn) Code_1

如果應(yīng)用不想讓普通用戶見到“中間的更新值”,就需要讓讀取操作只讀取已經(jīng)提交的數(shù)據(jù),這就依賴于我們選擇的事務(wù)隔離級別。如果隔離級別過低,例如 READ UNCOMMITTED,就可能出現(xiàn)事務(wù) 2 先讀到事務(wù) 1 的未提交更新,最后又發(fā)現(xiàn)實際已經(jīng)回滾的數(shù)據(jù),從而產(chǎn)生數(shù)據(jù)不一致的問題。


小結(jié)

  • 并發(fā)是多用戶環(huán)境下數(shù)據(jù)庫系統(tǒng)必須解決的問題。

  • 不同的并發(fā)問題包括:丟失更新、臟讀、不可重復讀和幻讀。它們在不同場景下給數(shù)據(jù)一致性帶來不同挑戰(zhàn)。

  • SQL Server 提供了多種事務(wù)隔離級別(從 READ UNCOMMITTED 到 SERIALIZABLE 以及 SNAPSHOT),分別在性能和一致性上做出了不同的權(quán)衡。

  • 實際應(yīng)用中需要結(jié)合具體業(yè)務(wù)需求和系統(tǒng)壓力,選擇恰當?shù)母綦x級別與并發(fā)控制技術(shù)(如鎖管理、行版本控制、樂觀并發(fā)控制等),才能在高并發(fā)環(huán)境下既保證數(shù)據(jù)一致性又維持良好的性能表現(xiàn)。

希望本文能幫助你更深入地理解 SQL Server 中的并發(fā)原理和常見問題。在后續(xù)探討中,可以結(jié)合實際業(yè)務(wù)邏輯與測試案例來進一步驗證哪種隔離級別或并發(fā)控制手段最為合適。祝你在數(shù)據(jù)庫并發(fā)處理方面取得更加理想的性能與一致性!


該文章在 2024/12/24 9:49:04 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運作、調(diào)度、堆場、車隊、財務(wù)費用、相關(guān)報表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點,圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務(wù)都免費,不限功能、不限時間、不限用戶的免費OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
亚洲中文字幕欧美高清 | 伊伊综合网在线视频免费 | 亚洲人成在线天堂 | 亚洲精品无播放器在线观看 | 欧美日韩成人一区精品高免费专区 | 一本精品99久久精品66 |