Sql-Server

未更改數據時送出或回滾 SQLServer-SQLTransaction

  • May 8, 2021

我們在後端使用SqlTransaction類來訪問儲存在 MS-SQLServer 中的數據。

在某些情況下,我們肯定知道此事務沒有更改任何數據(並且沒有發生錯誤)。所以問題是:在這些情況下如何關閉交易?我們應該使用Commit()or Rollback(),還是不使用這兩個功能或其他東西?目的是找到以“合理”的方式完成交易的最高效的方式。

我的建議

反過來想。ROLLBACK僅當您有理由撤消自事務開始以來的所有內容時才發出 a ,例如異常、錯誤狀態或明確希望撤消所有內容。如果一切都按計劃進行,那麼您應該始終COMMIT.

為什麼?

發出 aROLLBACK將導致 SQL Server 撤消在事務中執行的任何工作。

即使您“知道” SQL Server 沒有更改數據,發出 a 也沒有任何好處,ROLLBACK除非您希望 SQL Server 撤消更改,因為您擔心無意的更改。如果您 100% 確定沒有任何變化,那麼我可以 100% 確信您應該發出 aCOMMIT代替。

如果您的程式碼所做的更改在技術上是更新的,但在邏輯上沒有更改,那麼 aROLLBACK將是額外的工作。

這是一個例子:

首先,讓我們創建一個新鮮、乾淨和原始的新數據庫。它像新床單一樣乾淨清新:

CREATE DATABASE RollMeBack;

ALTER DATABASE RollMeBack SET RECOVERY SIMPLE;

USE RollMeBack
GO
--Create a table
CREATE TABLE dbo.WidgetQueue (
   QueueID bigint identity(1,1),
   QueueStatus char(1),
   SomeOtherStuff varchar(500)
   CONSTRAINT PK_WidgetQueue PRIMARY KEY CLUSTERED (QueueID)
);
GO
--put some stuff in it
INSERT INTO dbo.WidgetQueue (QueueStatus, SomeOtherStuff)
SELECT  QueueStatus    = CASE c2. column_id%3
                          WHEN 0 THEN 'Q' 
                          WHEN 1 THEN 'S' 
                          WHEN 2 THEN 'L' 
                        END,
       SomeOtherStuff = c1.name + c2.name
FROM sys.columns AS c1
CROSS JOIN sys.columns AS c2;
GO 5

CHECKPOINT;

BACKUP DATABASE RollMeBack TO DISK = 'NUL;';

那將是一張漂亮的大桌子。它可能不需要那麼大。現在,讓我們重新CHECKPOINT來看看事務日誌。我得到 3 行返回。不管他們說什麼,現在都不重要。

USE RollMeBack
GO
CHECKPOINT;

SELECT *
FROM sys.fn_dblog(NULL,NULL);

現在,我們將在事務中進行更新,從邏輯上講不會進行任何更改,但實際上會更新一堆行。對我來說,這將在 2 秒內執行,並更新 1892100 行,將狀態設置為與目前狀態完全相同的值。

BEGIN TRANSACTION
   UPDATE q
   SET QueueStatus = 'S'
   FROM dbo.WidgetQueue AS q
   WHERE QueueStatus = 'S';

現在,讓我們再次查看事務日誌:

SELECT *
FROM sys.fn_dblog(NULL,NULL);

💥 對我來說,返回 2916 行——這些是 2916 條日誌記錄,在事務日誌中記錄了事務。你的旅費可能會改變。這些日誌記錄基本上是對 SQL Server 在您的事務期間所做的事情的衡量。所有這些日誌記錄都告訴我們 SQL Server 在該事務中做了一大堆工作。從邏輯上講,它的結果為零,並且數據看起來與開始時完全相同……除了 SQL Server 實際上更新了這些行。

如果我ROLLBACK現在發布,SQL Server 將撤消這些更新。從邏輯上講,這與不理會它們的結果相同,但是 SQL Server 只是按照它被告知的去做,它必須通過這 2916 條日誌記錄來解開它所做的事情,並確保它讓一切都保持原樣在交易開始時。

如果我改為發出 a COMMIT,SQL Server 只會說“OK。DONE!” 並記錄,COMMIT而不必解開已完成的工作。

在我們開始之前,讓我們刪除我們創建的用於測試的數據庫。

USE master
GO
DROP DATABASE RollMeBack;

其他注意事項

如果我的dbo.QueueStatus桌子上有觸發器怎麼辦?然後我的更新可能會引發一堆我沒有意識到但仍然很重要的其他工作。

您還讓開發人員有責任了解、理解和維護在該事務中完成的工作為零的事實。未來對應用程序的更改可能會引入導致更改應該被持久化的程式碼路徑——現在需要更新應用程序邏輯以知道不回滾。

記錄呢?即使只是在開發週期中將一些內容放入日誌表中以嘗試解決問題只是臨時日誌記錄,該日誌記錄也會被回滾。

引用自:https://dba.stackexchange.com/questions/291197