事务操作(BEGIN/COMMIT/ROLLBACK/SAVE TRANSACTION)
BEGIN TRANSACTION
标记一个显式本地事务的起始点。 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 { TRAN | TRANSACTION }
[ { transaction_name | @tran_name_variable }
[ WITH MARK [ 'description' ] ]
]
[ ; ]
参数
transaction_name
分配给事务的名称。 transaction_name 必须符合标识符规则,但标识符所包含的字符数不能大于 32。 仅在最外面的 BEGIN...COMMIT 或 BEGIN...ROLLBACK 嵌套语句对中使用事务名。 transaction_name 始终是区分大小写的,即使 SQL Server 实例不区分大小写也是如此。
@tran_name_variable
用户定义的、含有有效事务名称的变量的名称。 必须用 char、varchar、nchar 或 nvarchar 数据类型声明变量。 如果传递给该变量的字符多于 32 个,则仅使用前面的 32 个字符;其余的字符将被截断。
WITH MARK [ 'description' ]
指定在日志中标记事务。 description 是描述该标记的字符串。 长于 128 个字符的 description 先截断为 128 个字符,然后才存储到 msdb.dbo.logmarkhistory 表中。
如果使用了 WITH MARK,则必须指定事务名。 WITH MARK 允许将事务日志还原到命名标记。
COMMIT TRANSACTION
标志一个成功的隐性事务或显式事务的结束。仅当事务引用的所有数据在逻辑上都正确时,才应发出 COMMIT TRANSACTION 命令。 如果 @@TRANCOUNT 为 1,COMMIT TRANSACTION 使得自从事务开始以来所执行的所有数据修改成为数据库的永久部分,释放事务所占用的资源,并将 @@TRANCOUNT 减少到 0。如果 @@TRANCOUNT 大于 1,则 COMMIT TRANSACTION 使 @@TRANCOUNT 按 1 递减并且事务将保持活动状态。
如果所提交的事务是 Transact-SQL 分布式事务,COMMIT TRANSACTION 将触发 MS DTC 使用两阶段提交协议,以便提交所有涉及该事务的服务器。 如果本地事务跨越同一数据库引擎实例上的两个或多个数据库,则该实例将使用内部的两阶段提交来提交所有涉及该事务的数据库。当 @@TRANCOUNT 为 0 时发出 COMMIT TRANSACTION 将会导致出现错误;因为没有相应的 BEGIN TRANSACTION。
不能在发出一个 COMMIT TRANSACTION 语句之后回滚事务,因为数据修改已经成为数据库的一个永久部分。
仅当事务计数在语句开始处为 0 时,数据库引擎才会增加语句内的事务计数。
语法
COMMIT [ { TRAN | TRANSACTION } [ transaction_name | @tran_name_variable ] ] [ WITH ( DELAYED_DURABILITY = { OFF | ON } ) ]
[ ; ]
参数
transaction_name
SQL Server 数据库引擎忽略此参数。 transaction_name 指定由前面的 BEGIN TRANSACTION 分配的事务名称。 transaction_name 必须符合标识符规则,但不能超过 32 个字符。 transaction_name 通过向程序员指明 COMMIT TRANSACTION 与哪些 BEGIN TRANSACTION 相关联,可作为帮助阅读的一种方法。
@tran_name_variable
用户定义的、含有有效事务名称的变量的名称。 必须用 char、varchar、nchar 或 nvarchar 数据类型声明变量。 如果传递给该变量的字符数超过 32,则只使用 32 个字符,其余的字符将被截断。
DELAYED_DURABILITY
请求将此事务与延迟持续性一起提交的选项。 如果已用 DELAYED_DURABILITY = DISABLED 或DELAYED_DURABILITY = FORCED 更改了数据库,则忽略该请求。
ROLLBACK TRANSACTION
将显式事务或隐性事务回滚到事务的起点或事务内的某个保存点。 可以使用 ROLLBACK TRANSACTION 清除自事务的起点或到某个保存点所做的所有数据修改。 它还释放由事务控制的资源。ROLLBACK TRANSACTION 语句不生成显示给用户的消息。 如果在存储过程或触发器中需要警告,请使用 RAISERROR 或 PRINT 语句。 RAISERROR 是用于指出错误的首选语句。
语法
ROLLBACK { TRAN | TRANSACTION }
[ transaction_name | @tran_name_variable
| savepoint_name | @savepoint_variable ]
[ ; ]
参数
transaction_name
是为 BEGIN TRANSACTION 上的事务分配的名称。 transaction_name 必须符合标识符规则,但只使用事务名称的前 32 个字符。 嵌套事务时,transaction_name 必须是最外面的 BEGIN TRANSACTION 语句中的名称。 transaction_name 始终是区分大小写的,即使 SQL Server 实例不区分大小写也是如此。
@ tran_name_variable
用户定义的、含有有效事务名称的变量的名称。 必须用 char、varchar、nchar 或 nvarchar 数据类型声明变量。
savepoint_name
是 SAVE TRANSACTION 语句中的 savepoint_name。 savepoint_name 必须符合有关标识符的规则。 当条件回滚应只影响事务的一部分时,可使用 savepoint_name。
@ savepoint_variable
是用户定义的、包含有效保存点名称的变量的名称。 必须用 char、varchar、nchar 或 nvarchar 数据类型声明变量。
SAVE TRANSACTION
在事务内设置保存点。保存点可以定义在按条件取消某个事务的一部分后,该事务可以返回的一个位置。 如果将事务回滚到保存点,则根据需要必须完成其他剩余的 Transact-SQL 语句和 COMMIT TRANSACTION 语句,或者必须通过将事务回滚到起始点完全取消事务。 若要取消整个事务,请使用 ROLLBACK TRANSACTION transaction_name 语句。 这将撤消事务的所有语句和过程。在事务中允许有重复的保存点名称,但指定保存点名称的 ROLLBACK TRANSACTION 语句只将事务回滚到使用该名称的最近的 SAVE TRANSACTION。
语法
SAVE { TRAN | TRANSACTION } { savepoint_name | @savepoint_variable }
[ ; ]
参数
savepoint_name
分配给保存点的名称。 保存点名称必须符合标识符的规则,但长度不能超过 32 个字符。 transaction_name始终是区分大小写的,即使 SQL Server 实例不区分大小写也是如此。
@savepoint_variable
包含有效保存点名称的用户定义变量的名称。 必须用 char、varchar、nchar 或 nvarchar 数据类型声明变量。 如果长度超过 32 个字符,也可以传递到变量,但只使用前 32 个字符。
示例
以下示例说明如果活动事务是在执行存储过程之前启动的,如何使用事务保存点仅回滚存储过程所做的修改。
USE AdventureWorks2012; GO IF EXISTS (SELECT name FROM sys.objects WHERE name = N'SaveTranExample') DROP PROCEDURE SaveTranExample; GO CREATE PROCEDURE SaveTranExample @InputCandidateID INT AS -- 检查是否是在活动的事务里面调用该存储过程(嵌套事务) -- @TranCounter = 0 表示不是在活动事务里面调用 -- @TranCounter > 0表示在该存储过程调用之前已经有一个活动的事务 DECLARE @TranCounter INT; SET @TranCounter = @@TRANCOUNT; IF @TranCounter > 0 -- 在该存储过程调用之前已经有一个活动的事务。创建一个保存点,如果这个存储过程出错,只回滚到执行存储过程之前的操作。 SAVE TRANSACTION ProcedureSave; ELSE -- 创建一个新的事务 BEGIN TRANSACTION; -- Modify database. BEGIN TRY DELETE HumanResources.JobCandidate WHERE JobCandidateID = @InputCandidateID; . IF @TranCounter = 0 -- @TranCounter = 0 只在这个存储过程里面有事务,必须提交事务 COMMIT TRANSACTION; END TRY BEGIN CATCH -- 错误发生,需要去判断回滚级别 IF @TranCounter = 0 -- 事务只在此存储过程中,回滚整个事务 -- Roll back complete transaction. ROLLBACK TRANSACTION; ELSE -- 事务在此存储过程开始之前已经创建(嵌套事务) -- XACT_STATE(),用于报告当前正在运行的请求的用户事务状态的标量函数。 XACT_STATE 指示请求是否有活动的用户事务,以及是否能够提交该事务。 -- XACT_STATE() = 1 ,当前请求有活动的用户事务。 请求可以执行任何操作,包括写入数据和提交事务。 -- XACT_STATE() = 0,当前请求没有活动的用户事务。 -- XACT_STATE() = -1 ,当前请求具有活动的用户事务,但出现了致使事务被归类为无法提交的事务的错误。 请求无法提交事务或回滚到保存点;它只能请求完全回滚事务。 -- 请求在回滚事务之前无法执行任何写操作。 请求在回滚事务之前只能执行读操作。 事务回滚之后,请求便可执行读写操作并可开始新的事务。 IF XACT_STATE() <> -1 -- 回滚到此存储过程开始之前的错作。 ROLLBACK TRANSACTION ProcedureSave; -- 输出错误信息 DECLARE @ErrorMessage NVARCHAR(4000); DECLARE @ErrorSeverity INT; DECLARE @ErrorState INT; SELECT @ErrorMessage = ERROR_MESSAGE(); SELECT @ErrorSeverity = ERROR_SEVERITY(); SELECT @ErrorState = ERROR_STATE(); RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState ); END CATCH GO