SQL Server嵌套事务

一、@@TRANCOUNT

在将事务前,我们先来了解一下@@TRANCOUNT ,@@trancount返回上传执行begin transaction语句的事务计数。

1、每执行一次begin transaction语句@@trancount 将增加1。

2、执行rollback transaction 语句@@trancount将变为0,但执行rollback transaction savepoint_name语句@@trancount不会有影响。

declare @currntTranCount VARCHAR
set @currntTranCount=@@TRANCOUNT
print ‘未执行事务前全局@@TRANCOUNT:‘+@currntTranCount

begin transaction
set @currntTranCount=@@TRANCOUNT
print ‘执行事务后全局@@TRANCOUNT:‘+@currntTranCount

rollback transaction
set @currntTranCount=@@TRANCOUNT
print ‘回滚事务后全局@@TRANCOUNT:‘+@currntTranCount

输出:

  未执行事务前全局@@TRANCOUNT:0
  执行事务后全局@@TRANCOUNT:1
  回滚事务后全局@@TRANCOUNT:0

declare @currntTranCount VARCHAR
set @currntTranCount=@@TRANCOUNT
print ‘未执行事务前全局@@TRANCOUNT:‘+@currntTranCount

begin transaction
set @currntTranCount=@@TRANCOUNT
print ‘执行事务后全局@@TRANCOUNT:‘+@currntTranCount

save transaction savePoint_Tran1
set @currntTranCount=@@TRANCOUNT
print ‘保存事务点后全局@@TRANCOUNT:‘+@currntTranCount

rollback transaction savePoint_Tran1    --@@TRANCOUNT没受影响
set @currntTranCount=@@TRANCOUNT
print ‘回滚事务保存点后全局@@TRANCOUNT:‘+@currntTranCount

rollback transaction
set @currntTranCount=@@TRANCOUNT
print ‘回滚事务后全局@@TRANCOUNT:‘+@currntTranCount

输出:

  未执行事务前全局@@TRANCOUNT:0
  执行事务后全局@@TRANCOUNT:1
  保存事务点后全局@@TRANCOUNT:1
  回滚事务保存点后全局@@TRANCOUNT:1
  回滚事务后全局@@TRANCOUNT:0

3、执行commit transaction或commit work语句@@trancount将递减1。

declare @currntTranCount VARCHAR
set @currntTranCount=@@TRANCOUNT
print ‘未执行事务前全局@@TRANCOUNT:‘+@currntTranCount

begin transaction
set @currntTranCount=@@TRANCOUNT
print ‘执行事务后全局@@TRANCOUNT:‘+@currntTranCount

commit transaction
set @currntTranCount=@@TRANCOUNT
print ‘提交事务后全局@@TRANCOUNT:‘+@currntTranCount

输出:

  未执行事务前全局@@TRANCOUNT:0
  执行事务后全局@@TRANCOUNT:1
  提交事务后全局@@TRANCOUNT:0

4、ROLLBACK TRANSACTION (Transact-SQL):https://msdn.microsoft.com/zh-cn/library/ms181299.aspx

5、COMMIT TRANSACTION (Transact-SQL):https://msdn.microsoft.com/zh-cn/library/ms190295.aspx

二、嵌套事务

1、回滚嵌套事务:rollback transaction只能回滚最外面的事务名称或rollback transaction不指定某个事务名进行回滚;

如果执行rollback transaction transaction_innerTran,SQL会提示“无法回滚 transaction_innerTran。找不到该名称的事务或保存点。”,原因是transaction_innerTran不是最外层的事务;也就是说:回滚事务一回滚就所有事务都被回滚。

rollback transaction可以回滚某个事务保存点(SAVE TRANSACTION savePoint_Tran), 如ROLLBACK TRAN savePoint_Tran,但是回滚事务保存点不会使事务计数@@TRANCOUNT减少。

1)内层回滚事务存储过程

--嵌套事务:内层事务
CREATE PROCEDURE pro_InnerTransactionTest
AS
BEGIN
    declare @currntTranCount VARCHAR(50)
    set @currntTranCount=@@TRANCOUNT
    print ‘未执行内层事务前全局@@TRANCOUNT:‘+@currntTranCount

    begin transaction transaction_innerTran
    set @currntTranCount=@@TRANCOUNT
    print ‘执行内层事务后全局@@TRANCOUNT:‘+@currntTranCount

    rollback transaction transaction_innerTran
    --rollback transaction
    --rollback transaction transaction_outerTran    --rollback都报错
    set @currntTranCount=@@TRANCOUNT
    print ‘回滚内层事务后全局@@TRANCOUNT:‘+@currntTranCount

    return 0;
    --return 1;
END
GO

2)外层开启事务执行

--嵌套事务:外层执行
declare @currntTranCount varchar(50);
declare @result int;
set @currntTranCount=@@TRANCOUNT;
print ‘未执行外层事务前全局@@TRANCOUNT:‘+@currntTranCount;

begin transaction transaction_outerTran;
set @currntTranCount=@@TRANCOUNT;
print ‘执行外层事务后全局@@TRANCOUNT:‘+@currntTranCount;

execute @result = pro_InnerTransactionTest;

if(@result <= 0)
begin
    rollback transaction transaction_outerTran;
    set @currntTranCount=@@TRANCOUNT;
    print ‘回滚外层事务后全局@@TRANCOUNT:‘+@currntTranCount;

    return;
end
commit transaction transaction_outerTran
set @currntTranCount=@@TRANCOUNT;
print ‘提交外层事务后全局@@TRANCOUNT:‘+@currntTranCount;

输出:

未执行外层事务前全局@@TRANCOUNT:0
执行外层事务后全局@@TRANCOUNT:1
未执行内层事务前全局@@TRANCOUNT:1
执行内层事务后全局@@TRANCOUNT:2
消息 6401,级别 16,状态 1,过程 pro_InnerTransactionTest,第 13 行
无法回滚 transaction_innerTran。找不到该名称的事务或保存点。
回滚内层事务后全局@@TRANCOUNT:2
消息 266,级别 16,状态 2,过程 pro_InnerTransactionTest,第 0 行
EXECUTE 后的事务计数指示 BEGIN 和 COMMIT 语句的数目不匹配。上一计数 = 1,当前计数 = 2。
回滚外层事务后全局@@TRANCOUNT:0

2、提交嵌套事务:commit transaction 可以单独指定某个事务名,如transaction_outerTran,transaction_innerTran进行提交,但即使transaction_innerTran提交成功了,只要最外面的事务transaction_outerTran回滚,transaction_innerTran提交的数据也会被回滚的。

1)内层提交事务存储过程

--嵌套事务:内层事务
CREATE PROCEDURE pro_InnerTransactionTest
AS
BEGIN
    declare @currntTranCount VARCHAR(50)
    set @currntTranCount=@@TRANCOUNT
    print ‘未执行内层事务前全局@@TRANCOUNT:‘+@currntTranCount

    begin transaction transaction_innerTran
    set @currntTranCount=@@TRANCOUNT
    print ‘执行内层事务后全局@@TRANCOUNT:‘+@currntTranCount

    --rollback transaction transaction_innerTran
    --rollback transaction
    --rollback transaction transaction_outerTran    --rollback都报错
    --set @[email protected]@TRANCOUNT
    --print ‘回滚内层事务后全局@@TRANCOUNT:‘[email protected]

    commit transaction transaction_innerTran    --提交内层事务,外层回滚或提交事务都没报错

    return 0;
    --return 1;
END
GO

2)外层开启事务执行后输出:

未执行外层事务前全局@@TRANCOUNT:0
执行外层事务后全局@@TRANCOUNT:1
未执行内层事务前全局@@TRANCOUNT:1
执行内层事务后全局@@TRANCOUNT:2
回滚外层事务后全局@@TRANCOUNT:0  (或:提交外层事务后全局@@TRANCOUNT:0)

三、解决办法:

1)内层存储过程

--嵌套事务:内层事务
CREATE PROCEDURE pro_InnerTransactionTest
AS
BEGIN
    declare @currntTranCount varchar(50)
    declare @sumError int=0
    declare @isSingleTran bit=1    --是否单个事务而非嵌套事务

    set @currntTranCount=@@TRANCOUNT
    print ‘未执行内层事务前全局@@TRANCOUNT:‘+@currntTranCount

    SET XACT_ABORT ON    --设置事务回滚到原点
    --开始事务
    if (@currntTranCount=0)
     begin
        begin transaction transaction_innerTran
        set @isSingleTran=1;
        set @currntTranCount=@@TRANCOUNT
        print ‘执行内层事务后全局@@TRANCOUNT:‘+@currntTranCount
     end
    else
     begin
        save transaction savepoint_innerTran    --保存事务点
        set @isSingleTran=0;
        set @currntTranCount=@@TRANCOUNT
        print ‘保存内层事务点全局@@TRANCOUNT:‘+@currntTranCount
     end

    --UPDATE [dbo].[FinanceInfo] SET [Balance] = [Balance]+1000 WHERE [UserId] = 10001
    --set @sumError = @sumError + @@error
    --UPDATE [dbo].[FinanceInfo] SET [Balance] = [Balance]-1000 WHERE [UserId] = 10002
    --set @sumError = @sumError + @@error

    set @sumError=1; --手动测试

    if(@sumError = 0)
     begin
        if(@isSingleTran = 1)
         begin
            commit transaction transaction_innerTran
            set @currntTranCount=@@TRANCOUNT
            print ‘提交内层事务点全局@@TRANCOUNT:‘+@currntTranCount
         end
        else
         begin
            set @currntTranCount=@@TRANCOUNT
            print ‘返回内层全局@@TRANCOUNT:‘+@currntTranCount
            return 1;            --成功
         end
     end
    else
     begin
        if(@isSingleTran = 1)
         begin
            rollback transaction    --发生错误,回滚事务
            set @currntTranCount=@@TRANCOUNT
            print ‘回滚内层事务全局@@TRANCOUNT:‘+@currntTranCount
         end
        else
         begin
            rollback transaction savepoint_innerTran
            set @currntTranCount=@@TRANCOUNT
            print ‘回滚内层事务点全局@@TRANCOUNT:‘+@currntTranCount
            return 0;                --失败
         end
     end
END
GO

2)外层开启事务执行存储过程

--嵌套事务:外层执行
declare @currntTranCount varchar(50);
declare @result int;
set @currntTranCount=@@TRANCOUNT;
print ‘未执行外层事务前全局@@TRANCOUNT:‘+@currntTranCount;

begin transaction transaction_outerTran;
set @currntTranCount=@@TRANCOUNT;
print ‘执行外层事务后全局@@TRANCOUNT:‘+@currntTranCount;

execute @result = pro_InnerTransactionTest;

if(@result <= 0)
begin
    rollback transaction transaction_outerTran;
    set @currntTranCount=@@TRANCOUNT;
    print ‘回滚外层事务后全局@@TRANCOUNT:‘+@currntTranCount;

    return;
end
commit transaction transaction_outerTran
set @currntTranCount=@@TRANCOUNT;
print ‘提交外层事务后全局@@TRANCOUNT:‘+@currntTranCount;

--单个事务执行
declare @result INT
execute @result = pro_InnerTransactionTest;
select @result
时间: 2024-08-08 22:03:54

SQL Server嵌套事务的相关文章

十步优化SQL Server中的数据访问(转载)

原文地址:http://tech.it168.com/a2009/1125/814/000000814758.shtml 故事开篇:你和你的团队经过不懈努力,终于使网站成功上线,刚开始时,注册用户较少,网站性能表现不错,但随着注册用户的增多,访问速度开始变慢,一些用户开始发来邮件表示抗议,事情变得越来越糟,为了留住用户,你开始着手调查访问变慢的原因. 经过紧张的调查,你发现问题出在数据库上,当应用程序尝试访问/更新数据时,数据库执行得相当慢,再次深入调查数据库后,你发现数据库表增长得很大,有些表

SQL Server 全局变量

SQL Server中所有全局变量都使用两个@符号作为前缀 --[email protected]@error 最后一个T-SQL错误的错误号(目的是或得违反约束的错误号) insert into Subject values('测试工程师')--违反了约束 select @@ERROR --[email protected]@identity 最后一次插入的标示值 insert into Subject (SubjectName, ClassHour, GradeId) --SubjectId

SQL Server——事务嵌套

http://www.cnblogs.com/Kymo/archive/2008/05/14/1194161.html 先看一下SQL Server Online Help相关的说明 Begin Transaction:标记一个显式本地事务的起始点.BEGIN TRANSACTION 使 @@TRANCOUNT 按 1 递增. Rollback Transaction: 将显式事务或隐性事务回滚到事务的起点或事务内的某个保存点.(嵌套事务时,该语句将所有内层事务回滚到最外面的 BEGIN TRA

SQL Server事务

事务的特性 原子性:要么全部执行,要么全部不执行. 一致性:事务完成时,所有的数据都保持一致状态. 隔离性:一个并发事务要么修改另一个事务之前的状态,要么修改它之后的状态,不能在该事务运行时去修改的它的状态. 持久性:事务成功提交后,不能在次回滚到提交前的状态了. 事务以“begin tran”语句开始,以“commit tran”或“rollback tran”语句结束. 事务执行时注意事项 u 每个操作之后都要检查@@ERROR和@@ROWCOUNT的值.@ERROR:当前一个语句遇到错误,

T-SQL查询进阶--SQL Server中的事务与锁

为什么需要锁 在任何多用户的数据库中,必须有一套用于数据修改的一致的规则,当两个不同的进程试图同时修改同一份数据时,数据库管理系统(DBMS)负责解决它们之间潜在的冲突.任何关系数据库必须支持事务的ACID属性,所以在开始了解锁之前,首先简单了解一下数据库事务和事务的ACID属性. 原子性(Atomicity):原子性意味着数据库中的事务执行是作为原子.即不可在分,整个语句要么执行,要么不执行 一致性(Consistency):在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏.(唯一约

(转)SQLServer_十步优化SQL Server中的数据访问 二

原文地址:http://tech.it168.com/a2009/1125/814/000000814758_all.shtml 第五步:识别低效TSQL,采用最佳实践重构和应用TSQL 由于每个程序员的能力和习惯都不一样,他们编写的TSQL可能风格各异,部分代码可能不是最佳实现,对于水平一般的程序员可能首先想到的是编写TSQL实现需求,至于性能问题日后再说,因此在开发和测试时可能发现不了问题. 也有一些人知道最佳实践,但在编写代码时由于种种原因没有采用最佳实践,等到用户发飙的那天才乖乖地重新埋

SQL Server 2008的MSSQLSERVER 请求失败或服务未及时响应

我的是SQL server 2008R2, 以前可以正常的启动SQL server(SQLEXPRESS).SQL server(MSSQLSERVER),有几天没有打开了,就在昨天 开机之后就无法启动MSSQLSERVER了,提示的信息如下图: 快速解决办法如下: 第一步:打开事件查看器,查看windows日志,点击应用程序,查看windows错误日志 http://product.pconline.com.cn/itbk/software/win8/1211/3060037.html 第二步

【Kettle】4、SQL SERVER到SQL SERVER数据转换抽取实例

1.系统版本信息 System:Windows旗舰版 Service Pack1 Kettle版本:6.1.0.1-196 JDK版本:1.8.0_72 2.连接数据库 本次实例连接数据库时使用全局变量. 2.1 创建新转换:spoon启动后,点击Ctrl+N创建新转换 2.2 在新转换界面中,右键点击DB连接,系统会弹出[数据库连接]界面. windows系统环境下,可用${}获取变量的内容. 说明: 连接名称:配置数据源使用名称.(必填) 主机名称:数据库主机IP地址,此处演示使用本地IP(

Bootstrap + AngularJS+ Ashx + SQL Server/MySQL

去年年底12月,为适应移动端浏览需求,花了1个月时间学习Bootstrap,并将公司ASP网站重构成ASP.NET. 当时采取的网站架构: Bootstrap + jQuery + Ashx + SQL Server 时间紧,没人带,只能硬着头皮,最后如期完成,但是也遗留了几个问题. 问题: 1.页面查询条件太复杂,太多的checkbox,jQuery操作DOM虽然方便,但是组合成json提交给后端还是比较麻烦,有没有天然支持json的前端框架或者脚本语言? html控件做的任何修改,都自动保存