SQL Server死鎖中的會話隔離級別為序列化(Serializable)實驗測試

来源:https://www.cnblogs.com/kerrycode/archive/2019/04/03/10646837.html
-Advertisement-
Play Games

最近在分析SQL Server的死鎖時,發現一個比較有意思的現象,發現死鎖當中一個會話的隔離級別為序列化(Serializable),這個是讓人比較奇怪的地方,我們知道SQL Server資料庫的預設隔離級別為已提交讀(READ COMMITTED),除非人為設置事務隔離級別(TRANSACTION... ...


最近在分析SQL Server的死鎖時,發現一個比較有意思的現象,發現死鎖當中一個會話的隔離級別為序列化(Serializable),這個是讓人比較奇怪的地方,我們知道SQL Server資料庫的預設隔離級別為已提交讀(READ COMMITTED),除非人為設置事務隔離級別(TRANSACTION ISOLATION LEVEL),否則事務隔離級別會使用資料庫的預設隔離級別。在分析了死鎖相關的存儲過程後,沒有發現有人為修改事務隔離級別的地方。在分析過後,我們判斷應該是在應用程式代碼裡面有設置隔離級別,下麵我們通過一個小實驗來構造這樣的一個案例。

 

測試環境資料庫為AdventureWorks2014,如下所示,我簡單寫了一點C#代碼,截取黏貼部分C#代碼在此,在這段代碼中,我們使用TransactionScope,我們先更新Sales.SalesOrderDetail,然後查詢 [Sales].[SalesOrderHeader]的相關數據來綁定Grid控制項

 

try
       {
           using (TransactionScope scope = new TransactionScope())
           {
               using (SqlConnection conn = new SqlConnection(connString))
               {
                   string cmdText = "UPDATE Sales.SalesOrderDetail SET OrderQty=2 WHERE SalesOrderID=43659 AND SalesOrderDetailID=1;";
 
                   SqlCommand cmd = new SqlCommand(cmdText, conn);
 
                   conn.Open();
                   cmd.ExecuteNonQuery();
 
               }
               using (SqlConnection conn = new SqlConnection(connString))
               {
                   DataSet sqldataset = new DataSet(); 
                   string cmdText = "SELECT * FROM [Sales].[SalesOrderHeader] WHERE SalesOrderID=43659;";
 
                   SqlCommand cmd = new SqlCommand(cmdText, conn);
 
                   SqlDataAdapter sqladapter = new SqlDataAdapter(cmdText, conn);
 
                   sqladapter.Fill(sqldataset, "spt_values");
                   gvData.DataSource = sqldataset;
                  gvData.DataBind();
 
               }
               scope.Complete();
           }
       }
       catch (TransactionAbortedException exc)
       {
           log.Error("錯誤", exc);
       }

 

 

然後另外一個會話,就直接用SSMS開啟一個事務(懶得構造C#代碼案例,主要是太浪費時間了),主要執行下麵邏輯:

 

BEGIN TRAN
UPDATE [Sales].[SalesOrderHeader] SET SubTotal = SubTotal + 10 
WHERE SalesOrderID=43659;
 
 
WAITFOR DELAY '00:00:10';
 
SELECT  TOP 10 * FROM Sales.SalesOrderDetail
 
--ROLLBACK TRAN;

 

   執行上面SQL語句,然後運行最上面C#代碼,立馬就能構造出一個死鎖案例,如下截圖所示,測試環境為SQL Server 2014,我就使用擴展事件system_health捕獲的死鎖(當然,你可以使用任何方式,例如Profile或Trace捕獲死鎖相關信息),使用SQL將死鎖的XML信息查出

 

 

clip_image001

 

如下所示,你會看到使用TransactionScope的會話的隔離級別為isolationlevel="serializable (4)", 具體可以參考下麵死鎖的XML文件。

 

 

clip_image002

 

image

<deadlock>
  <victim-list>
    <victimProcess id="process17676e108" />
  </victim-list>
  <process-list>
    <process id="process17676e108" taskpriority="0" logused="384" waitresource="KEY: 7:72057594048479232 (0ca7b7436f59)" waittime="379" ownerId="46635671" transactionname="user_transaction" lasttranstarted="2019-04-02T23:26:21.150" XDES="0x17f0511f0" lockMode="S" schedulerid="1" kpid="13440" status="suspended" spid="61" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2019-04-02T23:26:21.147" lastbatchcompleted="2019-04-02T23:26:09.343" lastattention="1900-01-01T00:00:00.343" clientapp="Microsoft SQL Server Management Studio - Query" hostname="MyNB00021" hostpid="9728" loginname="test" isolationlevel="read committed (2)" xactid="46635671" currentdb="7" lockTimeout="4294967295" clientoption1="671090784" clientoption2="390200">
      <executionStack>
        <frame procname="adhoc" line="8" stmtstart="282" stmtend="368" sqlhandle="0x020000002a285923f5e38f7347b53337195c56a4a1bc33080000000000000000000000000000000000000000">
unknown    </frame>
      </executionStack>
      <inputbuf>
BEGIN TRAN
UPDATE [Sales].[SalesOrderHeader] SET SubTotal = SubTotal + 10 
WHERE SalesOrderID=43659;
 
 
  WAITFOR DELAY '00:00:10';
 
  SELECT  TOP 10 * FROM Sales.SalesOrderDetail   </inputbuf>
    </process>
    <process id="process175603c28" taskpriority="0" logused="436" waitresource="KEY: 7:72057594048544768 (6a8a6db47ef5)" waittime="4420" ownerId="46635065" transactionname="user_transaction" lasttranstarted="2019-04-02T23:25:36.807" XDES="0x1762fa9f0" lockMode="S" schedulerid="1" kpid="51760" status="suspended" spid="63" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2019-04-02T23:26:26.450" lastbatchcompleted="2019-04-02T23:25:36.807" lastattention="1900-01-01T00:00:00.807" clientapp=".Net SqlClient Data Provider" hostname="MyNB00021" hostpid="1700" loginname="kkk" isolationlevel="serializable (4)" xactid="46635065" currentdb="7" lockTimeout="4294967295" clientoption1="673316896" clientoption2="128056">
      <executionStack>
        <frame procname="AdventureWorks2014.Sales.iduSalesOrderDetail" line="18" stmtstart="982" stmtend="2448" sqlhandle="0x0300070076146e6c18e00a016ba3000000000000000000000000000000000000000000000000000000000000">
INSERT INTO [Production].[TransactionHistory]
                ([ProductID]
                ,[ReferenceOrderID]
                ,[ReferenceOrderLineID]
                ,[TransactionType]
                ,[TransactionDate]
                ,[Quantity]
                ,[ActualCost])
            SELECT 
                inserted.[ProductID]
                ,inserted.[SalesOrderID]
                ,inserted.[SalesOrderDetailID]
                ,'S'
                ,GETDATE()
                ,inserted.[OrderQty]
                ,inserted.[UnitPrice]
            FROM inserted 
                INNER JOIN [Sales].[SalesOrderHeader] 
                ON inserted.[SalesOrderID] = [Sales].[SalesOrderHeader].[SalesOrderID    </frame>
        <frame procname="adhoc" line="1" stmtstart="52" stmtend="262" sqlhandle="0x02000000abf4ee0ff24fea415c6f35709c721203030a173b0000000000000000000000000000000000000000">
unknown    </frame>
        <frame procname="adhoc" line="1" stmtend="186" sqlhandle="0x02000000b0cd40243d43ed1a51b1baa9cbf70d1628eae7880000000000000000000000000000000000000000">
unknown    </frame>
      </executionStack>
      <inputbuf>
UPDATE Sales.SalesOrderDetail SET OrderQty=2 WHERE SalesOrderID=43659 AND SalesOrderDetailID=1;   </inputbuf>
    </process>
  </process-list>
	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這是國外數據科學學習平臺DataCamp成員寫的一篇圖文《8步成為數據科學家》。我們具體來看下有哪些學習內容和學習資源。 ...
  • AIX 7.2 下Oracle 11.2.0.4 RAC資料庫root用戶在使用 /u01/app/11.2.0/grid/OPatch/opatch auto /soft/28813878 -ocmrf /soft/ocm.rsp 安裝11.2.0.4.20190115 PSU時,遇到 patch ...
  • Elasticsearch的映射(mapping)是什麼? 在創建索引時, 如何對不同的數據類型進行特殊的配置與操作? 映射(mapping)有哪些組成部分? 如何配置和更新mapping? 這篇文章通通告訴你. ...
  • 為什麼要配置主從同步? 如果一臺資料庫伺服器掛了,還有一個備用 為了方便配置,我採用兩台WinServer2003虛擬機: 1.前期準備工作:安裝好鏡像文件,VMTOOLS,MySQL5.5 我這裡以192.168.111.134為主伺服器(以下簡稱134) 打開my.ini文件: 在最下麵加上這些 ...
  • --轉載自 https://blog.csdn.net/sunny05296/article/details/81126548--以sysdba用戶登錄,查找需要刪除的用戶conn / as sysdba --查找用戶select * from dba_users;select username f ...
  • 1、先去下載綠色版的Mysql(https://cdn.mysql.com//archives/mysql-5.7/mysql-5.7.20-winx64.zip) 2、解壓縮到任意目錄(如D:\Mysql),並保證此目錄是根目錄,即訪問bin目錄的訪問路徑是(D:\Mysql\bin) 3、在D: ...
  • 查詢表空間所有相關信息sql:select * from dba_data_files; dba_data_files視圖欄位說明 ...
  • 管理oracle 11g RAC 常用命令1)、檢查集群狀態: [grid@rac02 ~]$ crsctl check cluster CRS-4537: Cluster Ready Services is online CRS-4529: Cluster Synchronization Serv ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...