以下内容根据此官方文档修改:http://technet.microsoft.com/zh-cn/library/ms189336(v=sql.105).aspx

嵌套事务的使用场景或者说目的主要是为了调用包含了事务的存储过程。不然没必要使用嵌套事务。

下列示例显示了嵌套事务的用途。在TransProc 存储过程中包含事务,在另外的代码中分别启动事务调用TransProc和不启动事务调用TransProc。

SET QUOTED_IDENTIFIER OFF;
GO
SET NOCOUNT OFF;
GO
USE AdventureWorks2008R2;
GO
CREATE TABLE TestTrans(Cola INT PRIMARY KEY,
Colb CHAR(3) NOT NULL);
GO
CREATE PROCEDURE TransProc @PriKey INT, @CharCol CHAR(3) AS
BEGIN TRANSACTION InProc
INSERT INTO TestTrans VALUES (@PriKey, @CharCol)
INSERT INTO TestTrans VALUES (@PriKey + 1, @CharCol)
COMMIT TRANSACTION InProc;
GO
/* Start a transaction and execute TransProc. */
BEGIN TRANSACTION OutOfProc;
GO
EXEC TransProc 1, 'aaa';
GO
/* Roll back the outer transaction, this will
roll back TransProc's nested transaction. */
ROLLBACK TRANSACTION OutOfProc;
GO
EXECUTE TransProc 3,'bbb';
GO
/* The following SELECT statement shows only rows 3 and 4 are
still in the table. This indicates that the commit
of the inner transaction from the first EXECUTE statement of
TransProc was overridden by the subsequent rollback. */
SELECT * FROM TestTrans;
GO

嵌套事务有以下特点:

1、SQL Server 数据库引擎将忽略内部事务的提交,除了将@@TRANCOUNT 减 1。内部事务的真正提交或者回滚是依靠最外部事务结束时进行的提交或者回滚。如果提交外部事务,也将提交内部嵌套事务。如果回滚外部事务,也将回滚所有内部事务,不管是否单独提交过内部事务。

2、但针对第1条,假如内部事务进行了提交动作(COMMIT TRANSACTION 或 COMMIT WORK),COMMIT只对当前所处的TRANSACTION起作用,也就是说即使COMMIT TRANSACTION transaction_name中的transaction_name是外部事务的名称,也不会提交该外部事务。这一条的重点在于内部事务无法提交外部事务。

3、@@TRANCOUNT 函数记录当前事务的嵌套级别,@@TRANCOUNT=0表示不在事务中,等于1表示在一个事务中,大于1表示处在嵌套事务中。每次 BEGIN TRANSACTION 语句使 @@TRANCOUNT 增加 1,每次 COMMIT TRANSACTION 或 COMMIT WORK 语句使 @@TRANCOUNT 减去 1,而只要有一个ROLLBACK就会使@@TRANCOUNT等于0.

4、ROLLBACK TRANSACTION 语句的 transaction_name只能是最外部事务的事务名称,使用内部事务名称是非法的。带最外部事务名称的ROLLBACK或者不带任何名称的ROLLBACK语句都将回滚所有嵌套事务,包括最外部事务。此时@@TRANCOUNT等于0。

5、针对第4条,这里特别需要说明的是:虽然这里说“ROLLBACK语句都将回滚所有嵌套事务,包括最外部事务”,但这里的前提是在最外层进行ROLLBACK,经过本人亲自实验,如果在内部事务中执行带最外部事务名称的ROLLBACK或者不带任何名称的ROLLBACK,则只回滚当前内部事务和已执行过的外部事务语句,此内部事务后续的外层事务将继续执行,并能成功修改数据,但后续外部事务中的所有rollback和commit都将不起作用,并提示错误信息,因为@@TRANCOUNT早已经等于0,数据库引擎找不到对应的BEGIN TRANSACTION。可以自己通过下面代码示例中的bad code示例进行验证。

以下最佳代码示范说明参考以下博文:http://www.cnblogs.com/Kymo/archive/2008/05/14/1194161.html

下面用代码进行解释,代码是根据Online Help Commit Transaction一节的代码修改而成,首先建立一个Table,然后开始三个Trasaction,中间人为触发一些错误,然后观察运行结果。

--Bad code
USE NORTHWIND;
--Create test table
IF Object_id(N'TestTran',N'U') IS NOT NULL
DROP TABLE TESTTRAN;
CREATE TABLE TESTTRAN (
COLA INT PRIMARY KEY,
COLB CHAR(3)); --Variable for keeping @@ERROR
DECLARE @_Error INT;
SET @_Error = 0; --Begin 3 nested transaction
BEGIN TRANSACTION OUTERTRAN;
BEGIN TRANSACTION INNER1;
BEGIN TRANSACTION INNER2;
INSERT INTO TESTTRAN VALUES (3,'ccc');--Inner2
RAISERROR('Inner2 error', 16, 1)
IF @@ERROR = 0
COMMIT TRANSACTION INNER2;
ELSE
ROLLBACK TRANSACTION ;
INSERT INTO TESTTRAN VALUES (2,'bbb');--Inner1
IF @@ERROR = 0
COMMIT TRANSACTION INNER1;
ELSE
ROLLBACK TRANSACTION ;
INSERT INTO TESTTRAN VALUES (1,'aaa');--OuterTran --RAISERROR ('OuterTran error',16,1)
IF @@ERROR = 0
COMMIT TRANSACTION OuterTran;
ELSE
ROLLBACK TRANSACTION;
SELECT * FROM TESTTRAN (NOLOCK);
SELECT @@Trancount;

上述代码当内层事务发生错误时,并不能正常Rollback,因为Rollback把@@Trancount变成了0,所以后面的Commit语句就找不到对应的Transaction了。解决问题的关键就是Rollback时要判断@@Trancount,当@@Trancount等于1时进行Rollback进行回滚,否则执行Commit把@@Trancount-1,同时把@@Error传到外层事务交给外层事务处理。微软的原文是没有问题的,但是这种情况比较简单,我们一眼就能看出哪个是内层事务,哪个是外层事务,一共嵌套了几层,如果是SP调用呢?你不知道你的SP会被谁调用,也不知道会被嵌套几层。

下面看一下怎么处理内层事务的错误(何时Rollback, Commit及错误的传递)

--Good code
USE NORTHWIND; --Create test table
IF Object_id(N'TestTran',N'U') IS NOT NULL
DROP TABLE TESTTRAN;
CREATE TABLE TESTTRAN (
COLA INT PRIMARY KEY,
COLB CHAR(3)); --Variable for keeping @@ERROR
DECLARE @_Error INT;
SET @_Error = 0; --Begin 3 nested transaction
BEGIN TRANSACTION OUTERTRAN;
BEGIN TRANSACTION INNER1;
BEGIN TRANSACTION INNER2;
INSERT INTO TESTTRAN VALUES (3,'ccc');--Inner2 --raiserror('Inner2 error', 16, 1)
SET @_Error = @@ERRORIF @_Error = 0
COMMIT TRAN INNER2;
ELSE
IF @@TRANCOUNT > 1
COMMIT TRANSACTION INNER2;
ELSE
ROLLBACK TRANSACTION INNER2;
INSERT INTO TESTTRAN VALUES (2,'bbb');--Inner1
IF @_Error = 0
SET @_Error = @@ERRORIF @_Error = 0
COMMIT TRAN INNER1;
ELSE
IF @@TRANCOUNT > 1
COMMIT TRANSACTION INNER1;
ELSE
ROLLBACK TRANSACTION INNER1;
INSERT INTO TESTTRAN VALUES (1,'aaa');--OuterTran
RAISERROR ('OuterTran error',16,1) -- rollback transaction OuterTran
SET @_Error = @_Error + @@ERROR
IF @_Error = 0
COMMIT TRAN OUTERTRAN;
ELSE
IF @@TRANCOUNT > 1
COMMIT TRANSACTION;
ELSE
ROLLBACK TRANSACTION OUTERTRAN;
SELECT * FROM TESTTRAN (NOLOCK)

考虑到SP的调用,我们开发SP时应该在最后把@@ERROR返回供调用者检查。另外测试注意检查一下@@Trancount,有时结果看似正确,但是如果@@Trancount不等于0,说明我们的代码出了问题。

sql 嵌套事务学习笔记的更多相关文章

  1. 【SQL Server学习笔记】Delete 语句、Output 子句、Merge语句

    原文:[SQL Server学习笔记]Delete 语句.Output 子句.Merge语句 DELETE语句 --建表 select * into distribution from sys.obj ...

  2. SQL server2005学习笔记(一)数据库的基本知识、基本操作(分离、脱机、收缩、备份、还原、附加)和基本语法

    在软件测试中,数据库是必备知识,假期闲里偷忙,整理了一点学习笔记,共同探讨. 阅读目录 基本知识 数据库发展史 数据库名词 SQL组成 基本操作 登录数据库操作 数据库远程连接操作 数据库分离操作 数 ...

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

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

  4. sql注入学习笔记,什么是sql注入,如何预防sql注入,如何寻找sql注入漏洞,如何注入sql攻击 (原)

    (整篇文章废话很多,但其实是为了新手能更好的了解这个sql注入是什么,需要学习的是文章最后关于如何预防sql注入) (整篇文章废话很多,但其实是为了新手能更好的了解这个sql注入是什么,需要学习的是文 ...

  5. 郝斌–SQL Server2005学习笔记

    数据库(Database)狭义上是指存储数据的仓库,广义上包含对数据进行存储和管理的软件(DBMS)和数据本身.数据库由表.关系和操作组成. 一.数据库简介 1.为什么需要数据库 数据库简化了对数据的 ...

  6. sql注入学习笔记 详解篇

    sql注入的原理以及怎么预防sql注入(请参考上一篇文章) https://www.cnblogs.com/KHZ521/p/12128364.html (本章主要针对MySQL数据库进行注入) sq ...

  7. SQl语句学习笔记(二)

    merge into        when matched then...  when not mached then... merge into t_road_pre_parameter a fr ...

  8. SQL语句学习笔记

    从外部EXCEl文件导入sqlserver数据库操作命令 reconfigure reconfigure go select * into abc1_1 from OPENROWSET('MICROS ...

  9. SQL server 学习笔记1

    1.查询安装的排序规则选项喝当前的排序规则服务器属性 select * from fn_helpcollations(); 2.查看当前服务器的排序规则 select serverproperty(' ...

随机推荐

  1. Jersey+Spring+Maven(转)

    spring和maven的搭建参考相关文档.本文只介绍与jersey有关配置. 一.jersey在maven中的依赖包 <!-- jersey --> <dependency> ...

  2. JIRA Cannot Start Due to 'unable to clean the cache directory: /opt/jira/plugins/.osgi-plugins/felix'

    Symptoms After restarting JIRA, the following error appeared: JIRA Startup Failed You cannot access ...

  3. 【转】eclipse内存设置,tomcat内存设置,查看内存大小

    原文网址:http://www.cnblogs.com/youngjoy/p/4239978.html 首先可以通过java/jdk/bin下的java visualVM查看eclipse的内存大小和 ...

  4. Javascript 母羊生小羊问题,递归

    农场买了一只小羊,这种羊在第一年是小羊,第二年的年底会生一只小羊,第三年不生小羊,第四年的年底还会再生下一只小羊,第五年就死掉了. 要计算N年时农场里有几只羊. [凡是碰到“一生二.二生三.三生万物” ...

  5. javaweb要点复习 jsp和servlet

    jsp:就是java server page ,  html嵌入java  ,所以更方面显示(V) serlet,就是服务器端小程序 java中嵌入html,更方面业务处理. jsp执行过程 1)客户 ...

  6. 网页局部刷新的办法。javascript+frame 或者ajax原理

    <frame>标签 + javascriptajax (DWR \ jquery \ extjs \ vs 下的ScriptManager和UpdatePanel控件)

  7. yum puppet 并整合控制台

    上篇说了下在ubuntu12.04上安装puppet,安装的版本为puppet2.7.11版本,今天尝试了下在CentOS6.4系统上安装puppet 3.1.1版本,本文参考chenshake的文章 ...

  8. spark高级排序彻底解秘

    排序,真的非常重要! RDD.scala(源码) 在其,没有罗列排序,不是说它不重要! 1.基础排序算法实战 2.二次排序算法实战 3.更高级别排序算法 4.排序算法内幕解密 1.基础排序算法实战 启 ...

  9. Java 字符转码之UTF-8转为GBK/GB2312

    java跟python类似的做法,在java中字符串的编码是java修改过的一种Unicode编码,所以看到java中的字符串,心理要默念这个东西是java修改过的一种Unicode编码的编码. pa ...

  10. 如何判断Linux是否适合你

    如果你厌烦了windows,或者想延长旧pc的寿命,也或者想给小孩使用一款os,linux都能满足你. 开源操作系统linux的关键优势: - 免费的. - 大部分linux软件也是免费的. - li ...