一、@@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 @currntTranCount=@@TRANCOUNT
--print '回滚内层事务后全局@@TRANCOUNT:'+@currntTranCount 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

SQL Server嵌套事务的更多相关文章

  1. sql server 学习笔记 (nested transaction 嵌套事务)

    什么时候会用到嵌套事务 ? 为了代码复用,我们会写许多的储蓄过程,而中间如果需要使用到 transaction 难免就会发生嵌套了. sql server 并不直接支持嵌套事务. 但它可以用一些招式来 ...

  2. sql server中嵌套事务*

    转自 https://www.cnblogs.com/guanjie20/archive/2013/02/17/2914488.html 我们在写事务时经常遇到的问题如下: 消息 266,级别 16, ...

  3. SQL Server 2014 新特性——内存数据库

    SQL Server 2014 新特性——内存数据库 目录 SQL Server 2014 新特性——内存数据库 简介: 设计目的和原因: 专业名词 In-Memory OLTP不同之处 内存优化表 ...

  4. SQL Server简洁查询正在运行的进程SQL

    通常我们可以使用 sp_who2 我们希望更加简洁的信息,下面这个查询使用系统表sys.sysprocesses,以及sys.dm_exec_sql_text做OUTER APPLY. T-SQL是这 ...

  5. SQL SERVER 分布式事务(DTC)

    BEGIN DISTRIBUTED TRANSACTION指定一个由 Microsoft 分布式事务处理协调器 (MS DTC) 管理的 Transact-SQL 分布式事务的起始. 语法BEGIN ...

  6. SQL Server 全局变量

    SQL Server中所有全局变量都使用两个@符号作为前缀 --1.@@error 最后一个T-SQL错误的错误号(目的是或得违反约束的错误号) insert into Subject values( ...

  7. sql server 分布式事务

    使用分布式事务刚好可以解决集群同时更新多台SQL SERVER数据库,要么全部成功,要么全部回滚的需要. 原来微软早考虑到此方面的问题了. 下面背书,贴出微软官网上面的帮助文档: 分布式事务跨越两个或 ...

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

    原文地址:http://tech.it168.com/a2009/1125/814/000000814758_all.shtml 第五步:识别低效TSQL,采用最佳实践重构和应用TSQL 由于每个程序 ...

  9. SQL Server 数据库try catch 存储过程

    SQL Server 在生产环境中这样写存储过程的坑都避免了吗? 原文链接: http://www.cnblogs.com/chenmh/p/7856777.html 概述 最近因为业务的需求写了一段 ...

随机推荐

  1. 分类器、logistic回归

    相关性 1.相关性是一种测度,用来表示两个变量在同一方向上发生变化的程度,如果x和y在变化方向上相同,那么这两个变量就是正相关:如果变化方向相反,就是负相关:如果变量之间没有关系,那么相关性就是0. ...

  2. kafka安装与测试

    基于linux-Centos7.0环境先进行测试学习 Producer即生产者,向Kafka集群发送消息,在发送消息之前,会对消息进行分类,即Topic, Topic即主题,通过对消息指定主题可以将消 ...

  3. iview menu组件手动收起与展开

    本文主要介绍menu组件在有子菜单时如何手动的展开与收起. 展开: 在需要展开的地方先设置openname变量如this.openname = ["设置"]; 再在$nextTic ...

  4. jquery弹窗插件layer:layer.layui.com

    这两天在做抽奖转盘功能,浏览器自带的alert弹出框太low,本人又基本不会前端, 于是借鉴前人用fancybox插件做的效果 结果没看懂其写法(http://www.0101shop.com/goo ...

  5. 提高你的python:解释 yield 和 Generators(生成器)

    转自:http://www.oschina.net/translate/improve-your-python-yield-and-generators-explained 原文:http://www ...

  6. MTQQ 物联网

    这个是学校的SRP项目.去年12月做了大概3周. 直接摘个人总结报告如下: 在本次“学生研究计划”项目,研究课题是“基于JAVA的智能家居公众号”.根据课题要求之一:以微信作为媒介,实现智能设备的远程 ...

  7. JavaScript关于sha1加密

    function encodeUTF8(s) { var i, r = [], c, x; for (i = 0; i < s.length; i++) if ((c = s.charCodeA ...

  8. h5跳转

    <!doctype html> <html lang="en" style="width:100%; height:100%"> < ...

  9. 《Mysql 锁》

    一:什么是锁? - 锁是计算机协调多个进程或纯线程并发访问某一资源的机制. - 通俗的来说,锁是一种对资源的保护形式. 二:锁分类 - 表级锁 - 开销小,加锁快,没有死锁,锁定粒度大,发生锁冲突的概 ...

  10. Python中的锁

    一.全局解释器锁(GIL) 1.什么是全局解释器锁 在同一个进程中只要有一个线程获取了全局解释器(cpu)的使用权限,那么其他的线程就必须等待该线程的全局解释器(cpu)使用权消失后才能使用全局解释器 ...