1. 程式人生 > >SQLServer之建立顯式事務

SQLServer之建立顯式事務

顯式事務定義

顯式事務以 BEGIN TRANSACTION 語句開始,並以 COMMIT 或 ROLLBACK 語句結束。

備註

BEGIN TRANSACTION 使 @@TRANCOUNT 按 1 遞增。

BEGIN TRANSACTION 代表一點,由連線引用的資料在該點邏輯和物理上都一致的。 如果遇上錯誤,在 BEGIN TRANSACTION 之後的所有資料改動都能進行回滾,以將資料返回到已知的一致狀態。 每個事務繼續執行直到它無誤地完成並且用 COMMIT TRANSACTION 對資料庫作永久的改動,或者遇上錯誤並且用 ROLLBACK TRANSACTION 語句擦除所有改動。

BEGIN TRANSACTION 為發出本語句的連線啟動一個本地事務。 根據當前事務隔離級別的設定,為支援該連線所發出的 Transact-SQL 語句而獲取的許多資源被該事務鎖定,直到使用 COMMIT TRANSACTION 或 ROLLBACK TRANSACTION 語句完成該事務為止。 長時間處於未完成狀態的事務會阻止其他使用者訪問這些鎖定的資源,也會阻止日誌截斷。

雖然 BEGIN TRANSACTION 啟動一個本地事務,但是在應用程式接下來執行一個必須記錄的操作(如執行 INSERT、UPDATE 或 DELETE 語句)之前,它並不被記錄在事務日誌中。 應用程式能執行一些操作,例如為了保護 SELECT 語句的事務隔離級別而獲取鎖,但是直到應用程式執行一個修改操作後日志中才有記錄。

在一系列巢狀的事務中用一個事務名給多個事務命名對該事務沒有什麼影響。 系統僅登記第一個(最外部的)事務名。 回滾到其他任何名稱(有效的儲存點名除外)都會產生錯誤。 事實上,回滾之前執行的任何語句都不會在錯誤發生時回滾。 這些語句僅當外層的事務回滾時才會進行回滾。

如果在語句提交或回滾之前執行了如下操作,由 BEGIN TRANSACTION 語句啟動的本地事務將升級為分散式事務:

  • 執行一個引用連結伺服器上的遠端表的 INSERT、DELETE 或 UPDATE 語句。 如果用於訪問連結伺服器的 OLE DB 訪問介面不支援 ITransactionJoin 介面,則 INSERT、UPDATE 或 DELETE 語句會失敗。

  • 當啟用了 REMOTE_PROC_TRANSACTIONS 選項時,將呼叫遠端儲存過程。

    SQL Server 的本地副本成為事務控制器並且使用 Microsoft 分散式事務處理協調器 (MS DTC) 來管理分散式事務。

    使用 BEGIN DISTRIBUTED TRANSACTION 可以將事務作為分散式事務顯式執行。 有關詳細資訊,請參閱 BEGIN DISTRIBUTED TRANSACTION (Transact-SQL)。

    SET IMPLICIT_TRANSACTIONS 設定為 ON 時,BEGIN TRANSACTION 語句建立兩個巢狀的事務。 有關詳細資訊,請參閱 SET IMPLICIT_TRANSACTIONS (Transact-SQL)

標記的事務

WITH MARK 選項使事務名被置於事務日誌中。 將資料庫還原到早期狀態時,可使用標記事務代替日期和時間。 有關詳細資訊,請參閱 使用標記的事務一致地恢復相關的資料庫的事務(完全恢復模式)和 RESTORE (Transact-SQL)。

另外,若要將一組相關資料庫恢復到邏輯上一致的狀態,必須使用事務日誌標記。 標記可由分散式事務置於相關資料庫的事務日誌中。 將這組相關資料庫恢復到這些標記將產生一組在事務上一致的資料庫。 在相關資料庫中放置標記需要特殊的過程。

只有當資料庫由標記事務更新時,才在事務日誌中放置標記。 不修改資料的事務不被標記。

使用T-SQL指令碼建立顯式事務

語法:

--宣告資料庫引用
use 資料庫名稱;
go

begin { tran| transaction } [ { transaction_name | @tran_name_variable } [ with mark [ 'description' ] ]
begin
業務程式碼1;

save  { tran | transaction } { savepoint_name | @savepoint_variable };

rollback { tran | transaction } [ transaction_name | @tran_name_variable | savepoint_name | @savepoint_variable ];

commit { tran | transaction }  { transaction_name | @tran_name_variable } with(delayed_durability=on);

end
go

語法解析:

--begin transaction transaction_name
--適用範圍:SQL Server(從 2008 版開始)和 Azure SQL Database
--分配給事務的名稱。 transaction_name 必須符合識別符號規則,但識別符號所包含的字元數不能大於 32。 僅在最外面的 BEGIN...COMMIT 或 BEGIN...ROLLBACK 巢狀語句對中使用事務名。 
--transaction_name 始終區分大小寫,即使 SQL Server 例項不區分大小寫也是如此。

--begin transaction @tran_name_variable 
--適用範圍:SQL Server(從 2008 版開始)和 Azure SQL Database
--使用者定義的、含有有效事務名稱的變數的名稱。 必須使用 char、varchar、nchar 或 nvarchar 資料型別宣告該變數。 如果傳遞給該變數的字元多於 32 個,則僅使用前面的 32 個字元;其餘的字元將被截斷。

--with mark [ 'description' ]
--適用範圍:SQL Server(從 2008 版開始)和 Azure SQL Database
--指定在日誌中標記事務。 description 是描述該標記的字串。 在將長於 128 個字元的 description 儲存到 msdb.dbo.logmarkhistory 表中之前,先將其截斷為 128 個字元。
--如果使用了 WITH MARK,則必須指定事務名。 WITH MARK 允許將事務日誌還原到命名標記。

--save transaction savepoint_name
--分配給儲存點的名稱。 儲存點名稱必須符合識別符號的規則,但長度不能超過 32 個字元。 savepoint_name 始終區分大小寫,即使 SQL Server 例項不區分大小寫也是如此。

--save transaction @savepoint_variable 
--包含有效儲存點名稱的使用者定義變數的名稱。 必須使用 char、varchar、nchar 或 nvarchar 資料型別宣告該變數。 如果長度超過 32 個字元,也可以傳遞到變數,但只使用前 32 個字元。

--rollback { tran | transaction } [ transaction_name | @tran_name_variable | savepoint_name | @savepoint_variable ];
--將顯式事務或隱性事務回滾到事務的起點或事務內的某個儲存點。 可以使用 ROLLBACK TRANSACTION 清除自事務的起點或到某個儲存點所做的所有資料修改。 它還釋放由事務控制的資源。

--commit { tran | transaction } { transaction_name | @tran_name_variable };
--標誌一個成功的隱性事務或顯式事務的結束。 如果 @@TRANCOUNT 為 1,COMMIT TRANSACTION 使得自從事務開始以來所執行的所有資料修改成為資料庫的永久部分,釋放事務所佔用的資源,並將 @@TRANCOUNT 減少到 0。 
--如果 @@TRANCOUNT 大於 1,則 COMMIT TRANSACTION 使 @@TRANCOUNT 按 1 遞減並且事務將保持活動狀態。

--delayed_durability
--適用範圍:SQL Server 和 Azure SQL 資料庫
--請求將此事務與延遲持續性一起提交的選項。 如果已用 DELAYED_DURABILITY = DISABLED 或 DELAYED_DURABILITY = FORCED 更改了資料庫,則忽略該請求。 有關詳細資訊,請參閱主題控制事務持續性。

示例:

--宣告資料庫引用
use testss;
go

begin transaction explicittran
with mark '開啟一個顯式事務'
begin
declare @counts int =0;

insert into test1(name,sex,age,classid,height) values('事務測試','男','21','20','178');
set @[email protected]+(select @@ROWCOUNT);
save tran inserttran1;--回滾點一,事務已經插入了一條資料

insert into test2(name) values('事務測試');
set @[email protected]+(select @@ROWCOUNT);
save tran inserttran2;--回滾點二,事務已經插入了二條資料

insert into test3(name,sex,age,classid) values('事務班','男','asd','23');
set @[email protected]+(select @@ROWCOUNT);
save tran inserttran3;--回滾點三,事務已經插入了三條資料

--出錯回滾到回滾點
if @counts=3
rollback transaction inserttran3;
else if @counts=2
rollback transaction inserttran2;
else if @counts=1
rollback transaction inserttran1;

--提交事務或者回滾事務
if @counts<>0
commit transaction explicittran 
--with(delayed_durability=on)
;
else
rollback transaction explicittran;
end
go

示例結果: