交易 是一組不可分割的工作邏輯單元,包含一或多個 T-SQL 陳述式。這些陳述式要么**全部成功認可**,要么**全部失敗回滾**,資料庫永不會停留在中間狀態。
| 模式 | 說明 | 適用場景 |
|---|---|---|
| 自動認可 (預設) | 每條陳述式隱含交易,成功自動 COMMIT,失敗自動 ROLLBACK | 單一陳述式操作 |
| 顯式交易 | 開發者以 BEGIN TRAN 明確啟動,COMMIT/ROLLBACK 明確結束 | 多步驟業務邏輯、需原子性 |
| 隱含交易 | SET IMPLICIT_TRANSACTIONS ON 後,首條 DML 自動啟動交易,需顯式 COMMIT/ROLLBACK | 舊版移植、特定框架需求 |
BEGIN TRAN[SACTION] [tran_name | @tran_var] -- 啟動交易,可命名
COMMIT TRAN[SACTION] [tran_name | @tran_var] -- 認可交易
ROLLBACK TRAN[SACTION] [tran_name | @tran_var | savepoint_name] -- 回滾 (可到儲存點)
SAVE TRAN[SACTION] savepoint_name -- 設定儲存點 (部分回滾用)
@@TRANCOUNT -- 目前交易巢狀層級 (每 BEGIN +1, COMMIT -1, ROLLBACK 歸零)
| 隔離等級 | 髒讀 | 不可重複讀 | 虛讀 | 備註 |
|---|---|---|---|---|
| READ UNCOMMITTED | ✅ 可能 | ✅ 可能 | ✅ 可能 | 效能最好,極少用 |
| READ COMMITTED (預設) | ❌ | ✅ 可能 | ✅ 可能 | 平衡點,依賴共享鎖 |
| REPEATABLE READ | ❌ | ❌ | ✅ 可能 | 保持共享鎖至交易結束 |
| SNAPSHOT | ❌ | ❌ | ❌ | 資料列版本控制,需啟用 DB 選項 |
| SERIALIZABLE | ❌ | ❌ | ❌ | 範圍鎖,並發度最低 |
設定方式:SET TRANSACTION ISOLATION LEVEL READ COMMITTED; (僅影響目前工作階段後續交易)
CREATE PROCEDURE usp_UpdateOfficeRent
@OfficeID INT,
@NewHits INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ErrorSum INT = 0;
BEGIN TRANSACTION; -- 顯式啟動
-- 步驟 1:更新建立時間
UPDATE dbo.OfficeRent SET CreateTime = GETDATE() WHERE OfficeID = @OfficeID;
SET @ErrorSum += @@ERROR; -- 累計錯誤碼 (0=成功)
-- 步驟 2:更新點擊數
UPDATE dbo.OfficeRent SET Hits = @NewHits WHERE OfficeID = @OfficeID;
SET @ErrorSum += @@ERROR;
-- 判斷並處理
IF @ErrorSum <> 0
BEGIN
PRINT N'發生錯誤,執行回滾';
ROLLBACK TRANSACTION;
END
ELSE
BEGIN
PRINT N'全部成功,提交交易';
COMMIT TRANSACTION;
END
END
CREATE PROCEDURE usp_ModernTransaction
@Param INT
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION;
-- 核心業務邏輯
UPDATE Table1 SET Col1 = @Param WHERE ID = 1;
INSERT INTO Table2 (ColA) VALUES (@Param);
-- 故意製造錯誤測試
-- SELECT 1/0;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- XACT_STATE() = 1 可認可, -1 必須回滾, 0 無交易
IF XACT_STATE() = -1
ROLLBACK TRANSACTION;
ELSE IF XACT_STATE() = 1
COMMIT TRANSACTION; -- 視業務決定是否部分認可
-- 記錄錯誤至日誌表
INSERT INTO ErrorLog (ProcName, ErrorNumber, ErrorMessage, ErrorTime)
VALUES (OBJECT_NAME(@@PROCID), ERROR_NUMBER(), ERROR_MESSAGE(), SYSDATETIME());
THROW; -- 向上拋出,讓呼叫端知曉
END CATCH
END
以下 DDL/管理命令會隱含認可目前交易,無法回滾:
CREATE/ALTER/DROP DATABASEBACKUP/RESTORE DATABASE/LOGDISK INIT, RECONFIGUREUPDATE STATISTICSGRANT/REVOKE/DENYsp_configure 後的 RECONFIGURESQL Server 不支援真正的巢狀交易。BEGIN TRAN 只是遞增 @@TRANCOUNT,只有最外層的 COMMIT 才真正寫入磁碟;任一層 ROLLBACK 會將 @@TRANCOUNT 歸零並回滾全部。建議:
SAVE TRANSACTION 做部分回滾,或檢查 @@TRANCOUNT > 0 決定是否自行啟動。掌握 顯式交易、ACID、隔離等級、TRY...CATCH + XACT_STATE 現代模式,即能撰寫健壯、高並發的資料庫業務邏輯。記住:交易要短、要快、鎖定資源要少,是高效能系統的鐵律。