Sql-Server

被要求不使用事務並使用解決方法來模擬一個

  • September 20, 2019

幾年來我一直在開發 T-SQL,並且一直在深入探勘,繼續盡我所能學習該語言的各個方面。我最近開始在一家新公司工作,並收到了我認為關於交易的奇怪建議。永遠不要使用它們。相反,請使用模擬事務的解決方法。這來自我們的 DBA,他在一個數據庫中工作,處理大量事務,隨後出現大量阻塞。我主要工作的數據庫沒有遇到這個問題,我看到過去使用過事務。

我了解交易的阻塞是預期的,因為它的性質是這樣做的,如果您可以不使用交易而逃脫,那麼一定要這樣做。但是我有很多情況下每個語句都必須成功執行。如果一個失敗,他們都必須失敗。

我總是盡可能地縮小我的事務範圍,總是與 SET XACT_ABORT ON 一起使用,並且總是在 TRY/CATCH 內。

例子:

CREATE SCHEMA someschema;
GO


CREATE TABLE someschema.tableA
(id   INT NOT NULL IDENTITY(1, 1) PRIMARY KEY, 
ColA VARCHAR(10) NOT NULL
);
GO

CREATE TABLE someschema.tableB
(id   INT NOT NULL IDENTITY(1, 1) PRIMARY KEY, 
ColB VARCHAR(10) NOT NULL
); 
GO


CREATE PROCEDURE someschema.ProcedureName @ColA VARCHAR(10), 
                                         @ColB VARCHAR(10)
AS
SET NOCOUNT, XACT_ABORT ON;
BEGIN
BEGIN TRY
   BEGIN TRANSACTION;

   INSERT INTO someschema.tableA(ColA)
   VALUES(@ColA);

   INSERT INTO someschema.tableB(ColB)
   VALUES(@ColB);

--Implement error
   SELECT 1/0 

   COMMIT TRANSACTION;
END TRY
BEGIN CATCH
   IF @@trancount > 0
   BEGIN
       ROLLBACK TRANSACTION;
   END;
   THROW;
   RETURN;
END CATCH;
END;
GO

這是他們建議我做的。

GO



CREATE PROCEDURE someschema.ProcedureNameNoTransaction @ColA VARCHAR(10), 
                                                      @ColB VARCHAR(10)
AS
SET NOCOUNT ON;
BEGIN
BEGIN TRY
   DECLARE @tableAid INT;
   DECLARE @tableBid INT;

   INSERT INTO someschema.tableA(ColA)
   VALUES(@ColA);
   SET @tableAid = SCOPE_IDENTITY();

   INSERT INTO someschema.tableB(ColB)
   VALUES(@ColB);
   SET @tableBid = SCOPE_IDENTITY();

--Implement error
   SELECT 1/0 

END TRY
BEGIN CATCH
   DELETE FROM someschema.tableA
   WHERE id = @tableAid;

   DELETE FROM someschema.tableB
   WHERE id = @tableBid;

   THROW;

   RETURN;
END CATCH;
END;
GO

我向社區提出的問題如下。作為交易的可行解決方法,這是否有意義?

根據我對交易的了解以及解決方案的建議,我的看法是,不,這不是一個可行的解決方案,並且會引入許多故障點。

在建議的解決方法中,我看到發生了四個隱式事務。try 中的兩個插入,然後是 catch 中的刪除的另外兩個事務。它確實“撤消”了插入,但沒有回滾任何內容,因此實際上沒有回滾。

這是一個非常基本的例子來展示他們所建議的概念。我一直在執行的一些實際儲存過程使它們變得非常冗長且難以管理,因為在這個範例中“回滾”多個結果集與兩個參數值變得非常複雜,正如您可以想像的那樣。由於“回滾”現在是手動完成的,因此有機會因為真實而錯過某些東西。

我認為存在的另一個問題是超時或斷開連接。這還會回滾嗎?這是我對為什麼應該使用 SET XACT_ABORT ON 的理解,以便在這些情況下,事務將回滾。

提前感謝您的回饋!

您不能在 SQL Server (以及可能任何其他適當的 RDBMS)使用事務。在沒有顯式事務邊界 ( begin transactioncommit) 的情況下,每個 SQL 語句都會啟動一個新事務,該事務在語句完成(或失敗)後隱式送出(或回滾)。

將自己稱為“DBA”的人建議的事務模擬未能確保事務處理的四個必要屬性中的三個,因為它僅解決“軟”錯誤而​​不能處理“硬”錯誤,例如網路斷開、斷電、磁碟故障等。

  • 原子性:失敗。如果在您的偽事務中間某處發生“硬”錯誤,則更改將是非原子的。
  • 一致性:失敗。從上面可以看出,在“硬”錯誤之後,您的數據將處於不一致的狀態。
  • 隔離:失敗。並發偽事務可能會在您的偽事務完成之前更改您的偽事務修改的一些數據。
  • 持久性:成功。您所做的更改是持久的,數據庫伺服器將確保;這是您同事的方法唯一不能搞砸的事情。

鎖是一種廣泛使用且在經驗上很成功的方法,可確保各種事務或 RDBMS 中的事務的 ACIDity(此站點就是一個範例)。我發現一個隨機的 DBA 不太可能比數百甚至數千名電腦科學家和工程師提出更好的解決方案來解決並發問題,他們過去一直在建構一些有趣的數據庫系統,什麼,50?60年?(我意識到這作為“訴諸權威”的論點有些謬誤,但無論如何我都會堅持下去。)

總之,如果可以,請忽略您的“DBA”的建議,如果您有精神,請與它抗爭,如果出現特定的並發問題,請回到這裡。

有一些錯誤非常嚴重,以至於永遠不會進入 CATCH 塊。從文件

嚴重性為 20 或更高的錯誤會停止會話的 SQL Server 數據庫引擎任務處理。如果發生嚴重程度為 20 或更高的錯誤並且數據庫連接未中斷,則 TRY…CATCH 將處理該錯誤。

注意,例如客戶端中斷請求或斷開的客戶端連接。

當系統管理員使用 KILL 語句結束會話時。

編譯錯誤,例如語法錯誤,阻止批處理執行。

由於延遲名稱解析而發生的錯誤。

其中很多很容易通過動態 SQL 生成。您所展示的撤消語句不會保護您的數據免受此類錯誤的影響。

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