SQL Server並發處理存在就更新解決方案探討_MsSql
這篇文章主要和大家一起探討了SQL Server並發處理存在就更新的7種解決方案,具有一定的參考價值,有興趣的小伙伴們可以參考一下
前言
本節我們來講講並發中最常見的情況存在即更新,在並發中若未存在行記錄則插入,此時未處理好極容易出現插入重複鍵情況,本文我們來介紹對並發中存在就更新行記錄的七種方案並且我們來綜合分析最合適的解決方案。
探討存在就更新七種方案
首先我們來建立測試表
IF OBJECT_ID('Test') IS NOT NULL DROP TABLE Test CREATE TABLE Test ( Id int, Name nchar(100), [Counter] int,primary key (Id), unique (Name) ); GO
解決方案一 (開啟事務)
我們統一建立預存程序透過來SQLQueryStress來測試並發狀況,我們來看第一種情況。
IF OBJECT_ID('TestPro') IS NOT NULL DROP PROCEDURE TestPro; GO CREATE PROCEDURE TestPro ( @Id INT ) AS DECLARE @Name NCHAR(100) = CAST(@Id AS NCHAR(100)) BEGIN TRANSACTION IF EXISTS ( SELECT 1 FROM Test WHERE Id = @Id ) UPDATE Test SET [Counter] = [Counter] + 1 WHERE Id = @Id; ELSE INSERT Test ( Id, Name, [Counter] ) VALUES ( @Id, @Name, 1 ); COMMIT GO
#同時開啟100個執行緒與200個執行緒出現插入重複鍵的幾率比較少還是存在。
解決方案二(降低隔離等級為最低隔離等級UNCOMMITED)
IF OBJECT_ID('TestPro') IS NOT NULL DROP PROCEDURE TestPro; GO CREATE PROCEDURE TestPro ( @Id INT ) AS DECLARE @Name NCHAR(100) = CAST(@Id AS NCHAR(100)) SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED BEGIN TRANSACTION IF EXISTS ( SELECT 1 FROM Test WHERE Id = @Id ) UPDATE Test SET [Counter] = [Counter] + 1 WHERE Id = @Id; ELSE INSERT Test ( Id, Name, [Counter] ) VALUES ( @Id, @name, 1 ); COMMIT GO
此時問題依舊和解決方案一無異(如果降低級別為最低隔離級別,如果行記錄為空,前一事務如果未進行提交,當前事務也能讀取到該行記錄為空,如果當前事務插入進去並進行提交,此時前一事務再進行提交此時就會出現插入重複鍵問題)
解決方案三(提升隔離等級為最高等級SERIALIZABLE)
IF OBJECT_ID('TestPro') IS NOT NULL DROP PROCEDURE TestPro; GO CREATE PROCEDURE TestPro ( @Id INT ) AS DECLARE @Name NCHAR(100) = CAST(@Id AS NCHAR(100)) SET TRANSACTION ISOLATION LEVEL SERIALIZABLE BEGIN TRANSACTION IF EXISTS ( SELECT 1 FROM dbo.Test WHERE Id = @Id ) UPDATE dbo.Test SET [Counter] = [Counter] + 1 WHERE Id = @Id; ELSE INSERT dbo.Test ( Id, Name, [Counter] ) VALUES ( @Id, @Name, 1 ); COMMIT GO
在這種情況下更加糟糕,直接到會導致死鎖
#此時將隔離等級提升為最高隔離等級會解決插入重複鍵問題,但是對於更新來獲取排它鎖而未提交,而此時另外一個進程進行查詢獲取共享鎖此時將造成進程間相互阻塞從而造成死鎖,所以從此知最高隔離等級有時候能夠解決並發問題但是也會帶來死鎖問題。
解決方案四(提升隔離等級+良好的鎖定)
此時我們再來在新增最高隔離等級的基礎上增添更新鎖,如下:
IF OBJECT_ID('TestPro') IS NOT NULL DROP PROCEDURE TestPro; GO CREATE PROCEDURE TestPro ( @Id INT ) AS DECLARE @Name NCHAR(100) = CAST(@Id AS NCHAR(100)) SET TRANSACTION ISOLATION LEVEL SERIALIZABLE BEGIN TRANSACTION IF EXISTS ( SELECT 1 FROM dbo.Test WITH(UPDLOCK) WHERE Id = @Id ) UPDATE dbo.Test SET [Counter] = [Counter] + 1 WHERE Id = @Id; ELSE INSERT dbo.Test ( Id, Name, [Counter] ) VALUES ( @Id, @Name, 1 ); COMMIT GO
#運行多次均未發現出現什麼異常,透過查詢資料時使用更新鎖而非共享鎖,這樣的話一來可以讀取資料但不阻塞其他事務,二來還確保自上次讀取資料後資料未被更改,這樣就解決了死鎖問題。似乎這樣的方案是可行得,如果是高並發不知是否可行。
解決方案五(提升隔離等級為行版本控制SNAPSHOT)
ALTER DATABASE UpsertTestDatabase SET ALLOW_SNAPSHOT_ISOLATION ON ALTER DATABASE UpsertTestDatabase SET READ_COMMITTED_SNAPSHOT ON GO IF OBJECT_ID('TestPro') IS NOT NULL DROP PROCEDURE TestPro; GO CREATE PROCEDURE TestPro ( @Id INT ) AS DECLARE @Name NCHAR(100) = CAST(@Id AS NCHAR(100)) BEGIN TRANSACTION IF EXISTS ( SELECT 1 FROM dbo.Test WHERE Id = @Id ) UPDATE dbo.Test SET [Counter] = [Counter] + 1 WHERE Id = @Id; ELSE INSERT dbo.Test ( Id, Name, [Counter] ) VALUES ( @Id, @Name, 1 ); COMMIT GO
上述解決方案也會出現插入重複鍵問題不可取。
解決方案六(提升隔離等級+表格變數)
IF OBJECT_ID('TestPro') IS NOT NULL DROP PROCEDURE TestPro; GO CREATE PROCEDURE TestPro ( @Id INT ) AS DECLARE @Name NCHAR(100) = CAST(@Id AS NCHAR(100)) DECLARE @updated TABLE ( i INT ); SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; BEGIN TRANSACTION UPDATE Test SET [Counter] = [Counter] + 1 OUTPUT DELETED.Id INTO @updated WHERE Id = @Id; IF NOT EXISTS ( SELECT i FROM @updated ) INSERT INTO Test ( Id, Name, counter ) VALUES ( @Id, @Name, 1 ); COMMIT GO
經過多次認證也是零錯誤,似乎透過表格變數形式實現可行。
解決方案七(提升隔離等級+Merge)
透過Merge關鍵來實現存在即更新否則則插入,同時我們應該注意設定隔離等級為SERIALIZABLE否則會出現插入重複鍵問題,程式碼如下:
IF OBJECT_ID('TestPro') IS NOT NULL DROP PROCEDURE TestPro; GO CREATE PROCEDURE TestPro ( @Id INT ) AS DECLARE @Name NCHAR(100) = CAST(@Id AS NCHAR(100)) SET TRAN ISOLATION LEVEL SERIALIZABLE BEGIN TRANSACTION MERGE Test AS [target] USING ( SELECT @Id AS Id ) AS source ON source.Id = [target].Id WHEN MATCHED THEN UPDATE SET [Counter] = [target].[Counter] + 1 WHEN NOT MATCHED THEN INSERT ( Id, Name, [Counter] ) VALUES ( @Id, @Name, 1 ); COMMIT GO
多次認證無論是並發100個執行緒或並發200個執行緒依然沒有例外資訊。
總結
本節我們詳細討論了在並發中如何處理存在即更新,否則即插入問題的解決方案,目前來講以上三種方案可行。
解決方案一(最高隔離等級+ 更新鎖定)
IF OBJECT_ID('TestPro') IS NOT NULL DROP PROCEDURE TestPro; GO CREATE PROCEDURE TestPro ( @Id INT ) AS DECLARE @Name NCHAR(100) = CAST(@Id AS NCHAR(100)) BEGIN TRANSACTION; UPDATE dbo.Test WITH ( UPDLOCK, HOLDLOCK ) SET [Counter] = [Counter] + 1 WHERE Id = @Id; IF ( @@ROWCOUNT = 0 ) BEGIN INSERT dbo.Test ( Id, Name, [Counter] ) VALUES ( @Id, @Name, 1 ); END COMMIT GO
# 暫時只能想到這三種解決方案,個人比較推薦方案一和方案三, 請問問您有何高見,請留下您的評論若可行,我將進行後續補充。
解決方案二(最高隔離等級 + 表格變數)
IF OBJECT_ID('TestPro') IS NOT NULL DROP PROCEDURE TestPro; GO CREATE PROCEDURE TestPro ( @Id INT ) AS DECLARE @Name NCHAR(100) = CAST(@Id AS NCHAR(100)) DECLARE @updated TABLE ( i INT ); SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; BEGIN TRANSACTION UPDATE Test SET [Counter] = [Counter] + 1 OUTPUT DELETED.Id INTO @updated WHERE Id = @Id; IF NOT EXISTS ( SELECT i FROM @updated ) INSERT INTO Test ( Id, Name, counter ) VALUES ( @Id, @Name, 1 ); COMMIT GO
解决方案三(最高隔离级别 + Merge)
IF OBJECT_ID('TestPro') IS NOT NULL DROP PROCEDURE TestPro; GO CREATE PROCEDURE TestPro ( @Id INT ) AS DECLARE @Name NCHAR(100) = CAST(@Id AS NCHAR(100)) SET TRAN ISOLATION LEVEL SERIALIZABLE BEGIN TRANSACTION MERGE Test AS [target] USING ( SELECT @Id AS Id ) AS source ON source.Id = [target].Id WHEN MATCHED THEN UPDATE SET [Counter] = [target].[Counter] + 1 WHEN NOT MATCHED THEN INSERT ( Id, Name, [Counter] ) VALUES ( @Id, @Name, 1 ); COMMIT GO
暂时只能想到这三种解决方案,个人比较推荐方案一和方案三, 请问您有何高见,请留下您的评论若可行,我将进行后续补充。
以上是SQL Server並發處理存在就更新解決方案探討_MsSql的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

暴雪戰網更新一直卡在45%怎麼解決?近期有很多人在更新軟體的時候,都是卡在45%的進度條,重啟多次還是會卡住,那麼這種情況應該要如何解決,我們可以透過重新安裝客戶端、切換地區、刪除文件的方式來處理,本期軟體教程就來分享操作步驟,希望能帶給更多的人幫助。 暴雪戰網更新一直卡在45%怎麼解決 一、客戶端 1、首先需要確認你的客戶是官網下載的官方版本。 2、如果不是的話,使用者可以進入亞服網址來進行下載。 3、進入以後點選右上角的下載就可以了。 注意:安裝的時候一定不要選擇簡體中文。

第七史詩已經確定將於2月22日中午11點進行不停機更新,本次更新為我們帶來超級多新的活動和內容,包括萊婭和甜蜜奇蹟限定召喚幾率UP、神秘卡池更新、特別支線故事奇蹟女僕王國第二週開啟等,一起來看看這次的更新。手遊更新時間表第七史詩2月22日更新:奇蹟女僕王國第二週開啟※「萊婭」&「甜蜜奇蹟」限定召喚幾率UP! ■限定召喚幾率UP時間:-2024/02/22(週四)11:00~2024/03/07(週四)10:59■角色屬性&職業:自然屬性、戰士■角色簡介:四人樂隊【奇蹟女僕王國】的副主唱兼貝

Angular.js是一種可自由存取的JavaScript平台,用於建立動態應用程式。它允許您透過擴展HTML的語法作為模板語言,以快速、清晰地表示應用程式的各個方面。 Angular.js提供了一系列工具,可協助您編寫、更新和測試程式碼。此外,它還提供了許多功能,如路由和表單管理。本指南將討論在Ubuntu24上安裝Angular的方法。首先,您需要安裝Node.js。 Node.js是一個基於ChromeV8引擎的JavaScript運行環境,可讓您在伺服器端執行JavaScript程式碼。要在Ub

提燈與地下城已經確定將於2月29日更新,更新之後會上線提燈與地下城重製版本,而且重製版本還會與哪吒傳奇聯動,重製版本還帶來全新職業,玩家可以直接轉職哦,地下城內容也將拓展,開放全新副本區域等。手遊更新時間表提燈與地下城2月29日更新:重製版╳「哪吒傳奇」聯動版本重點內容全新職業,邀您轉職什麼?提燈者竟然可以轉職了?如此酷炫的裝備真是讓人眼饞,聽說,轉職之後,提燈者還能學習很多超帥的技能,五郎直接驚呼:泰褲辣!哪吒傳奇,連結來襲!踩著那風火輪,乾坤圈手中拿♫~智勇雙全的小英雄:哪吒和小龍女,即將來臨

WindowsServerBackup是WindowsServer作業系統自帶的功能,旨在協助使用者保護重要資料和系統配置,並為中小型和企業級企業提供完整的備份和復原解決方案。只有執行Server2022及更高版本的使用者才能使用此功能。在本文中,我們將介紹如何安裝、解除安裝或重設WindowsServerBackup。如何重置Windows伺服器備份如果您的伺服器備份遇到問題,備份所需時間過長,或無法存取已儲存的文件,那麼您可以考慮重新設定WindowsServer備份設定。要重設Windows

一分鐘搞定:如何更新pip版本,需要具體程式碼範例隨著Python的快速發展,pip成為了Python套件管理的標準工具。然而,隨著時間的推移,pip版本也不斷更新,為了能夠使用最新的功能和修復可能的安全漏洞,更新pip版本是非常重要的。本文將介紹如何在一分鐘內快速更新pip,並提供具體的程式碼範例。首先,我們需要打開命令列視窗。在Windows系統中,可以使用

小夥伴電腦出現這樣的故障,開啟「此電腦」和C碟檔案會提示「Explorer.EXEWindows無法存取指定裝置、路徑或檔案。你可能沒有適當的權限存取存取專案。」包括資料夾、檔案、此電腦、回收站等,雙擊都會彈出這樣的窗口,右鍵又是正常的。這是系統更新導致,如果你也遇到這樣的狀況,下面小編教大家如何解決。一,開啟登錄編輯程式Win+R,輸入regedit,或右鍵開始選單執行輸入regedit;二,定位登錄機「電腦\HKEY_CLASSES_ROOT\PackagedCom\ClassInd

Windows更新可能導致以下一些問題:1.相容性問題:某些應用程式、驅動程式或硬體裝置可能與新的Windows更新不相容,導致它們無法正常運作或崩潰。 2.效能問題:有時,Windows更新可能會導致系統變得更慢或出現效能下降的情況。這可能是由於新的功能或改進需要更多資源來運作。 3.系統穩定性問題:某些用戶報告稱,在安裝Windows更新後,系統可能會出現意外的崩潰或藍屏錯誤。 4.資料遺失:在罕見的情況下,Windows更新可能會導致資料遺失或檔案損壞。這是為什麼在進行任何重要的更新之前,請備份您
