[MSSQL]使用Transation機制確保資料異動正確性

在上一篇提到 try/catch處理機制 避免SQL發生例外錯誤時繼續往下執行,

但是有時候的狀況是當我開始執行時有其中一筆發生例外錯誤想要所有做的事當作沒發生過呢?

在這時會需要使用到交易(Transation)機制,這裡我們簡稱為Tran,

(原理還沒了解透徹,暫時是以以下方法理解)

而他的原理是每一個Table在建立時會有.mdf檔和.ldf檔的實體檔案

當我們在執行交易(Transation)時,所有結果會存在.ldf裡,而當我們確定資料異動完畢後才會將資料複製進.mdf檔內

這有個值得注意的問題是,完成後資料是複製而不是搬移,因此.ldf檔會愈來愈大,之後會再和大家聊.ldf檔最佳釋放的方法

在這裡示範Transation的使用方法,故意創造一個除以零的錯誤

Transation機制示範
IF OBJECT_ID('tempdb.dbo.#TBL') IS NOT NULL DROP TABLE #TBL
CREATE TABLE #TBL(ITEM INT)

BEGIN TRY
BEGIN TRAN--開始執行TRAN

INSERT INTO #TBL(ITEM) VALUES(1)
INSERT INTO #TBL(ITEM) VALUES(2)
SELECT 2/0
INSERT INTO #TBL(ITEM) VALUES(3)
SELECT * FROM #TBL
COMMIT TRAN --提交TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN --還原TRAN
--DB查詢用
	SELECT ERROR_NUMBER() AS ErrorNumber,
		   ERROR_MESSAGE() AS ErrorMessage,
		   ERROR_LINE() AS ErrorLine,
		   ERROR_PROCEDURE() AS ErrorProcedure,
		   ERROR_SEVERITY() AS ErrorSeverity,
		   ERROR_STATE() AS ErrorState

--系統拋回訊息用
	DECLARE @ErrorMessage As VARCHAR(1000) = CHAR(10)+'錯誤代碼:' +CAST(ERROR_NUMBER() AS VARCHAR)
											+CHAR(10)+'錯誤訊息:'+	ERROR_MESSAGE()
											+CHAR(10)+'錯誤行號:'+	CAST(ERROR_LINE() AS VARCHAR)
											+CHAR(10)+'錯誤程序名稱:'+	ISNULL(ERROR_PROCEDURE(),'')
	DECLARE @ErrorSeverity As Numeric = ERROR_SEVERITY()
	DECLARE @ErrorState As Numeric = ERROR_STATE()
	RAISERROR( @ErrorMessage, @ErrorSeverity, @ErrorState);--回傳錯誤資訊
END CATCH

Transation機制建議搭配Try/Catch機制一起使用,當發生例外錯誤時,則將TRY裡面的TRAN做還原動作

執行完畢資料表結果如下

雖然成功INSERT兩筆,第三筆才失敗,但是因為Transation機制做了還原的動作

另外Transation機制有兩個特點非常值得注意的是

1.當沒有提交(Commit)或是還原(Rollback)時,當有其他人在查詢交易內的Table時,會一直卡在查詢中,直到該次交易被提交或還原或是資料庫重啟之後

2.因為Transation會將結果暫時存在Cache等待承認該筆交易後才會存進實體檔案內,因此不管是Commit或RollBack都會非常的緩慢以及耗效能,

因此建議只有在異動資料的時候在包TRAN就好,其他的查詢確認就別包了吧。

如有觀念錯誤,請不吝指教