SQL Server 的巢狀交易不是真正的巢狀。語法雖允許 BEGIN TRAN 巢狀、COMMIT 內層、ROLLBACK 內層,但引擎僅識別最外層交易。@@TRANCOUNT 只是計數器,不代表獨立交易上下文。
CREATE DATABASE NestedXactsAreNotReal;
GO
USE NestedXactsAreNotReal;
GO
ALTER DATABASE NestedXactsAreNotReal SET RECOVERY SIMPLE;
GO
CREATE TABLE t1 (c1 INT IDENTITY, c2 CHAR(8000) DEFAULT 'a');
CREATE CLUSTERED INDEX t1c1 ON t1(c1);
GO
SET NOCOUNT ON;
GO
-- 測試:外層插入 1000 列,內層插入 1000 列
BEGIN TRAN OuterTran;
GO
INSERT INTO t1 DEFAULT VALUES;
GO 1000
BEGIN TRAN InnerTran;
GO
INSERT INTO t1 DEFAULT VALUES;
GO 1000
SELECT @@TRANCOUNT, COUNT(*) FROM t1; -- 結果:2, 2000
GO
-- 嘗試只回滾內層
ROLLBACK TRAN InnerTran;
GO
-- 錯誤 6401:找不到該名稱的交易或儲存點。
-- 正確語法:ROLLBACK TRAN(無名稱)或 ROLLBACK TRAN OuterTran
ROLLBACK TRAN;
GO
SELECT @@TRANCOUNT, COUNT(*) FROM t1; -- 結果:0, 0(全部回滾)
COMMIT 內層:僅遞減 @@TRANCOUNT,不寫入磁碟,資料仍可被外層 ROLLBACK 回滾。ROLLBACK 內層(無名稱或外層名稱):回滾整個外層交易,將 @@TRANCOUNT 歸零。SAVE TRAN savepoint_name 與 ROLLBACK TRAN savepoint_name。永遠不要在程式碼中使用巢狀交易。 它是記錄異常增長、鎖定時間過長、邏輯錯誤的常見根因。若需模組化交易控制,請在單一交易內使用儲存點,或重構為扁平化交易邊界。