我有我幾乎總是遵循一個模式,在這裏,如果我需要在交易收官的操作,我這樣做:後如何避免在嵌套存儲過程中的嵌套事務中使用重複的保存點名稱?
BEGIN TRANSACTION
SAVE TRANSACTION TX
-- Stuff
IF @error <> 0
ROLLBACK TRANSACTION TX
COMMIT TRANSACTION
那服務是我不夠好,在過去,但多年的使用這個模式(和複製上面的代碼),我突然發現了一個完全衝擊的缺陷。
很多時候,我將有一個存儲過程調用其他存儲過程,所有這些過程都使用相同的模式。我發現(以我的成本)是因爲我在任何地方都使用相同的保存點名稱,所以我可以進入一個情況,即我的外部事務部分提交 - 恰恰與我試圖實現的原子性相反。
我已經彙集了一個展示問題的例子。這是一個單獨的批處理(沒有嵌套的存儲過程),所以它看起來有點奇怪,因爲你可能不會在同一批次中使用同一個保存點名稱兩次,但是我的真實世界的場景太容易發佈。
CREATE TABLE Test (test INTEGER NOT NULL)
BEGIN TRAN
SAVE TRAN TX
BEGIN TRAN
SAVE TRAN TX
INSERT INTO Test(test) VALUES (1)
COMMIT TRAN TX
BEGIN TRAN
SAVE TRAN TX
INSERT INTO Test(test) VALUES (2)
COMMIT TRAN TX
DELETE FROM Test
ROLLBACK TRAN TX
COMMIT TRAN TX
SELECT * FROM Test
DROP TABLE Test
當我執行此操作時,它列出了一個值爲「1」的記錄。換句話說,即使我回滾了外部交易,,表中也添加了一條記錄。
發生什麼事是在外層的ROLLBACK TRANSACTION TX
回滾到內層的最後SAVE TRANSACTION TX
。現在我寫完了這些,我可以看到它背後的邏輯:服務器正在回顧日誌文件,將其視爲線性事務流;它不理解嵌套事務(或者在我的真實世界場景中,通過調用其他存儲過程)所隱含的嵌套/層次結構。
因此,顯然,我需要開始使用唯一的保存點名稱,而不是盲目地使用「TX」。但是 - 這是我終於明白的地方 - 是否有辦法以可複製的方式執行此操作,以便我可以在任何地方使用相同的代碼?我能以某種方式自動生成保存點名稱嗎?做這種事情是否有慣例或最佳做法?
每次開始交易時都不難想出一個獨一無二的名字(可以根據SP名稱或其他名稱),但我確實擔心最終會出現衝突 - 而且您不會這樣做,知道這件事,因爲,而不是導致其只是默默地破壞你的數據的錯誤... :-(
如果您進一步閱讀本答案頂部的鏈接,您會看到「@savepoint_variable ...超過32個字符可以傳遞給變量,但只會使用前32個字符「。這意味着你的CONVERT(char(23),GETDATE(),121)很可能會被截斷,直到你的保存點名稱(以及可能的程序名稱結束)。 – Lee 2016-08-24 19:16:43