送出後回滾
我有多個數據庫會話,其中一個由於凍結的應用程序而阻止了其他數據庫會話。有在多個會話上執行的事務。由於其他會話上的鎖定請求超時,我需要殺死頭部阻止程序。殺死該會話後,其他使用者報告了數據失去。我很確定他們已經送出了他們的交易,但他們似乎仍然被回滾了。他們甚至可以證明這一點,因為一些文件已經列印出來,之後失去了數據。
是否有可能由於另一個會話的回滾而回滾已送出的事務?我認為不會,但在閱讀了COMMIT 文件後,我有疑問。它說:
如果@@TRANCOUNT 大於1,COMMIT TRANSACTION 將@@TRANCOUNT 僅遞減1,並且事務保持活動狀態。
閱讀它說的TRANCOUNT 文件:
返回目前連接上發生的 BEGIN TRANSACTION 語句數。
那麼目前連接是否與會話相同,或者多個會話可以共享同一個連接(可能通過池化)?如果他們可以分享,這與交易有什麼關係?這些活動事務是否會在稍後甚至在它們被送出之後被回滾?
$$ edit $$更清楚地說,一些使用者沒有獲得鎖定超時,因為他們的數據沒有與頭部攔截器衝突。他們送出了交易,但這些交易似乎在殺死頭部阻止程序後被回滾。 **$$ Update 2018-03-29 $$**在發生新事件後,我有機會在問題發生時對其進行調查。事務日誌得出結論,問題是一個從未送出的嵌套事務。導致問題的應用程序沒有被凍結,因此使用者在關閉應用程序之前從未註意到它。那時他失去了他的數據,因為事務被回滾了。我接受了可能的最佳答案,那就是告訴我不可能回滾已送出的事務。我想這真的不可能,只是很難找到真正的問題。
通常,交易恰好是其中之一
- 堅定的
- 回滾
送出的事務永遠不會回滾。
這是所有 RDBMS 的運作方式,基於ACID 原則
現在,在一些不同的情況下,這條規則可能看起來被打破了。但事實並非如此。
不過,在我們查看這些情況之前,不同的使用者會話不共享連接。每個使用者/客戶端都有一個到 SQL 的連接,並且所有連接都是相互隔離的。連接池不會影響這一點。
保存點
你可以保存一個事務並回滾到這個保存點,
也就是說,如果您使用保存點,您可以部分送出/回滾,但我從未見過有人在現實生活中的程式碼中這樣做。我不會再展開了。
嵌套事務
您可以嵌套事務,但它們實際上並沒有任何意義
簡單地說,即使@@TRANCOUNT 可以大於一,SQL Server 也沒有真正的嵌套事務。
- A begin 將@@TRANCOUNT 加一
- 回滾會將@@TRANCOUNT 設置為零
- 送出將@@TRANCOUNT 減一
更長的解釋在這個 SO answer