SQL Server - 在事務回滾期間我有什麼訪問權限?
正如標題所說,在回滾事務時,我是否具有對整個數據庫的讀/寫訪問權限?
還是僅對事務未寫入的表進行讀/寫訪問?什麼是鎖定行為?
如果我確實有讀取權限,當我讀取一個事務回滾寫入的表時會發生什麼(查詢是失敗還是只是等待)?
抱歉這些問題,我試過線上閱讀(ROLLBACK TRANSACTION (Transact-SQL)),但似乎沒有觸及到這個深度。
答案實際上很大程度上取決於您的隔離級別、正在回滾的事務持有什麼類型的鎖,以及您的非回滾會話試圖做什麼。
步驟 1) 什麼被鎖定?
在
ROLLBACK
發布之前,該事務已經完成工作並獲得了鎖。您可以通過查看查看這些鎖的詳細資訊sys.dm_tran_locks
:SELECT tl.resource_type, tl.resource_associated_entity_id, tl.request_status, tl.request_mode, tl.request_session_id, tl.resource_description FROM sys.dm_tran_locks tl WHERE tl.request_session_id = <ROLLBACK session id>;
和
resource_type
會resource_associated_entity_id
告訴你什麼被鎖定。如果resource_type
是“對象”,那麼resource_associated_entity_id
是object_id
. 如果resource_type
是“Key”或“Page”,resource_associated_entity_id
則為hobt_id
. 有更多類型要解碼,但這兩種涵蓋了大多數場景。SELECT tl.resource_type, tl.resource_associated_entity_id,tl.resource_database_id, CASE WHEN resource_type = 'OBJECT' THEN object_name(tl.resource_associated_entity_id,tl.resource_database_id) WHEN resource_type IN ('KEY','PAGE') THEN object_name(p.object_id) END AS resource_name, tl.request_status, tl.request_mode, tl.request_session_id, tl.resource_description FROM sys.dm_tran_locks tl LEFT JOIN sys.partitions p ON p.hobt_id = tl.resource_associated_entity_id AND tl.resource_database_id = db_id() WHERE tl.request_session_id = <ROLLBACK session id>;
最後,鎖定模式提供了有關如何使用該鎖定的資訊。BOL列出了所有不同的鎖定模式。
第 2 步:什麼會被阻止?
如果正在回滾的事務沒有鎖定對象,則
ROLLBACK
不會阻塞其他會話。那部分很容易。這些鎖是否會導致阻塞將取決於您的隔離級別以及您要執行的操作。Paul White有一個關於隔離級別的非常深入的系列,您可以閱讀該系列以了解很多細節。
讀、寫和隔離級別的不同組合會產生不同的阻塞結果。一般來說,寫總是阻塞寫。但是,寫入可能會或可能不會阻止讀取。在 SQL Server 的預設
READ_COMMITTED
隔離級別下,寫入將阻止讀取。如果您正在使用READ_COMMITTED_SNAPSHOT
(又名“RCSI”又名“使用行版本控制讀取送出”),那麼寫入不會阻塞讀取。在所有情況下,如果另一個會話被 中的會話阻塞
ROLLBACK
,則等待會話將一直等到ROLLBACK
釋放鎖。
您應該從兩個不同的角度來看待這一點 - 發出 ROLLBACK 的連接和所有其他連接的角度。
發出連接很簡單:不,您無權訪問。ROLLBACK 是同步執行的。在 ROLLBACK 成功之前,此連接無法執行任何其他操作。(如果它因任何原因失敗,您將處於痛苦的世界中,並且可能與 MS 支持人員交談。)
對於所有其他連接,沒有變化。在 ROLLBACK 啟動之前他們可以做的任何事情,他們都可以在它進行時做。事務 B 是否可以讀取被事務 A 鎖定的值將取決於 A 持有的鎖的類型以及 B 正在執行的隔離級別。對於那些提供最高數據完整性保證的組合,B 通常會等待 A 完成並釋放鎖。如果 B 設法讀取 A 已鎖定的值,並且 A 更改了該值,DBMS 將不會神奇地進入應用程序並更改以前讀取的值。請注意,這與說如果 B 第二次讀取同一行將收到相同的結果不同。
隨著事務執行工作(即更改各行中的值),鎖定被佔用1. 這些鎖可防止 DBMS 中的各種並發活動破壞彼此的工作。它們允許多個使用者連接到單個數據庫並並行執行工作,同時保持數據完整。它們有助於實現並發和隔離——兩個非常值得熟悉的大主題。可以對行、頁或表進行鎖定。如果單個行被一個連接鎖定,則所有其他行將可供其他連接使用。如果整個表被鎖定,那麼在釋放鎖之前,沒有其他連接可以在該表上工作。(我在這裡滑過整個世界的精妙之處以保持重點。)隨著工作的進行,這些鎖被逐步獲取,一次一個。此外,“之前”和“之後”
在 ROLLBACK 期間,DBMS 通過日誌文件反向處理所做的每個更改,獲取“之前”值並將它們替換到表的數據中。當它返回到 BEGIN TRANSACTION 語句時,所有表的值都將恢復到它們開始時的狀態,並且我們保證沒有其他使用者會因為鎖定而執行沖突更改。
可以想像,ROLLBACK 可以在撤消更改時釋放鎖。然而,我寧願認為它不會。由於最初正在完成工作,可能有幾個原因需要鎖定一行,比如它被更新了兩次。要使 ROLLBACK 上的增量鎖釋放起作用,必須記錄這兩個更新以及鎖本身,這是很多內部簿記,希望這是一個罕見的事件。所以我寧願認為所有的鎖都被持有,直到所有的數據都回到它開始的時候,然後所有的鎖都被釋放了。
此時,所有其他事務都可以繼續進行,就好像回滾事務從未存在一樣。那些等待先前鎖定的物品的人從沉睡中醒來,並允許訪問現在解鎖的值。
1這方面有很多變化。隔離級別很重要。多值並發控制很重要。我限制討論以盡可能簡潔地回答實際問題,而不涉及所有配置選項、警告和特殊情況。