SQL Server——事务嵌套

http://www.cnblogs.com/Kymo/archive/2008/05/14/1194161.html

先看一下SQL Server Online Help相关的说明

  1. Begin Transaction:标记一个显式本地事务的起始点。BEGIN TRANSACTION 使 @@TRANCOUNT 按 1 递增。
  2. Rollback Transaction: 将显式事务或隐性事务回滚到事务的起点或事务内的某个保存点。(嵌套事务时,该语句将所有内层事务回滚到最外面的 BEGIN TRANSACTION 语句。无论在哪种情况下,ROLLBACK TRANSACTION 都将 @@TRANCOUNT 系统函数减小为 0。ROLLBACK TRANSACTION savepoint_name 不减小 @@TRANCOUNT。)
  3. Commit Transaction:标志一个成功的隐性事务或显式事务的结束。如果 @@TRANCOUNT 为 1,COMMIT TRANSACTION 使得自从事务开始以来所执行的所有数据修改成为数据库的永久部分,释放事务所占用的资源,并将 @@TRANCOUNT 减少到 0。如果 @@TRANCOUNT 大于 1,则 COMMIT TRANSACTION 使 @@TRANCOUNT 按 1 递减并且事务将保持活动状态。

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

1--Bad code
 2USE NORTHWIND;
 3--Create test table
 4IF Object_id(N‘TestTran‘,N‘U‘) IS NOT NULL
 5  DROP TABLE TESTTRAN;
 6
 7CREATE TABLE TESTTRAN (
 8  COLA INT   PRIMARY KEY,
 9  COLB CHAR(3));
10
11--Variable for keeping @@ERROR
12DECLARE  @_Error INT;
13SET @_Error = 0;
14
15--Begin 3 nested transaction
16BEGIN TRANSACTION OUTERTRAN;
17BEGIN TRANSACTION INNER1;
18BEGIN TRANSACTION INNER2;
19
20INSERT INTO TESTTRAN VALUES     (3,‘ccc‘);--Inner2
21
22RAISERROR(‘Inner2 error‘, 16, 1)
23IF @@ERROR = 0
24    COMMIT TRANSACTION INNER2;
25ELSE
26    ROLLBACK TRANSACTION ;
27  
28INSERT INTO TESTTRAN VALUES     (2,‘bbb‘);--Inner1
29
30IF @@ERROR = 0
31    COMMIT TRANSACTION INNER1;
32ELSE
33    ROLLBACK TRANSACTION ;
34  
35INSERT INTO TESTTRAN VALUES     (1,‘aaa‘);--OuterTran
36
37--RAISERROR (‘OuterTran error‘,16,1)
38                        
39IF @@ERROR = 0
40    COMMIT TRANSACTION OuterTran;
41ELSE
42    ROLLBACK TRANSACTION;    
43
44SELECT * FROM   TESTTRAN (NOLOCK);
45SELECT @@Trancount;

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

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

1--Good code
 2USE NORTHWIND;
 3
 4--Create test table
 5IF Object_id(N‘TestTran‘,N‘U‘) IS NOT NULL
 6  DROP TABLE TESTTRAN;
 7
 8CREATE TABLE TESTTRAN (
 9  COLA INT   PRIMARY KEY,
10  COLB CHAR(3));
11
12--Variable for keeping @@ERROR
13DECLARE  @_Error INT;
14SET @_Error = 0;
15
16--Begin 3 nested transaction
17BEGIN TRANSACTION OUTERTRAN;
18BEGIN TRANSACTION INNER1;
19BEGIN TRANSACTION INNER2;
20
21INSERT INTO TESTTRAN VALUES     (3,‘ccc‘);--Inner2
22
23--raiserror(‘Inner2 error‘, 16, 1)
24SET    @_Error = @@ERROR              
25IF    @_Error = 0
26    COMMIT TRAN INNER2;
27ELSE
28  IF @@TRANCOUNT > 1
29    COMMIT TRANSACTION INNER2;
30  ELSE
31       ROLLBACK TRANSACTION INNER2;
32  
33INSERT INTO TESTTRAN VALUES     (2,‘bbb‘);--Inner1
34
35IF @_Error = 0
36    SET @_Error = @@ERROR                
37IF @_Error = 0
38    COMMIT TRAN INNER1;
39ELSE
40  IF @@TRANCOUNT > 1
41    COMMIT TRANSACTION INNER1;
42  ELSE
43    ROLLBACK TRANSACTION INNER1;
44  
45INSERT INTO TESTTRAN VALUES     (1,‘aaa‘);--OuterTran
46
47RAISERROR (‘OuterTran error‘,16,1)
48
49--    rollback transaction OuterTran
50SET @_Error = @_Error + @@ERROR
51                        
52IF @_Error = 0
53    COMMIT TRAN OUTERTRAN;
54ELSE
55    IF @@TRANCOUNT > 1
56        COMMIT TRANSACTION;
57    ELSE
58        ROLLBACK TRANSACTION OUTERTRAN;    
59
60SELECT * FROM   TESTTRAN (NOLOCK)

时间: 2024-10-23 14:33:19

SQL Server——事务嵌套的相关文章

SQL Server 事务嵌套

原文:SQL Server 事务嵌套 示例代码: DECLARE @TranCounter INT; SET @TranCounter = @@TRANCOUNT; IF @TranCounter > 0 -- Procedure called when there is -- an active transaction. -- Create a savepoint to be able -- to roll back only the work done -- in the procedure

SQL Server 事务隔离级别详解

原文:SQL Server 事务隔离级别详解 标签: SQL SEERVER/MSSQL SERVER/SQL/事务隔离级别选项/设计数据库事务级别 SQL 事务隔离级别 概述 隔离级别用于决定如果控制并发用户如何读写数据的操作,同时对性能也有一定的影响作用. 步骤 事务隔离级别通过影响读操作来间接地影响写操作:可以在回话级别上设置事务隔离级别也可以在查询(表级别)级别上设置事务隔离级别.事务隔离级别总共有6个隔离级别:READ UNCOMMITTED(未提交读,读脏),相当于(NOLOCK)R

Sql Server 事务日志

Sql Server事务日志文件是数据库文件的重要组成部分,事务日志主要用来存放数据库的修改记录.数据库为了得到更高的写入效率和性能,同时保证ACID特性,数据在写入时,会将更新先写入事务日志,因为事务日志是连写的,所以写事务会比较快.简单来说,顺序写入时,磁盘的磁头会保持在一定的区域内连续写入,而数据写入数据文件时,有随机性,磁盘的磁头移动消耗的时间要比数据写入日志文件时多. Sql Server对于事务日志文件的管理,是将日志文件在逻辑上分成若干个文件(VLFS),方便管理. 创建一个1M的

如何处理SQL Server事务复制中的大事务操作

如何处理SQL Server事务复制中的大事务操作 事务复制的工作机制 事务复制是由 SQL Server 快照代理.日志读取器代理和分发代理实现的.快照代理准备快照文件(其中包含了已发布表和数据库对象的架构和数据),然后将这些文件存储在快照文件夹中,并在分发服务器中的分发数据库中记录同步作业. 日志读取器代理监视为事务复制配置的每个数据库的事务日志,并将标记为要复制的事务从事务日志复制到分发数据库中,分发数据库的作用相当于一个可靠的存储-转发队列. 分发代理将快照文件夹中的初始快照文件和分发数

SQL Server事务执行一半出错是否自动回滚整个事务 【转】

http://www.2cto.com/database/201308/234728.html SQL Server事务执行一半出错是否自动回滚整个事务 大家都知道SQL Server事务是单个的工作单元.如果某一事务成功,则在该事务中进行的所有数据修改均会提交,成为数据库中的永久组成部分.如果事务遇到错误且必须取消或回滚,则所有数据修改均被清除. 所以是不是说事务出错一定会回滚整个事物呢? 先看几个个例子: --createtable create table testrollback(idi

SQL Server事务日志分析

SQL Server事务日志分析 fn_dblog()和fn_dump_dblog()函数介绍 SQL Server有两个未公开的函数fn_dblog()和fn_dump_dblog()非常有用并且提供的信息量很大.你可以使用这些函数来获取100多列大量的有用信息. fn_dblog()用于分析数据库当前的事务日志文件,它需要两个参数,分别为事务开始LSN和结束LSN,默认为NULL,表示返回事务日志文件的所有日志记录. 例如: SELECT * FROM fn_dblog(null,null)

理解Sql Server 事务隔离层级(Transaction Isolation Level)

关于Sql Server 事务隔离级别,百度百科是这样描述的 隔离级别:一个事务必须与由其他事务进行的资源或数据更改相隔离的程度.隔离级别从允许的并发副作用(例如,脏读或虚拟读取)的角度进行描述. 隔离级别共5种: read uncommitted | 0 未提交读read committed | 1 已提交读repeatable read | 2 可重复读serializable | 3 可序列化snapshot 快照(2005版本以后新加) 以下面的图为例,在事务A中会根据条件读取TABLE

SQL Server 事务复制分发到订阅同步慢

原文:SQL Server 事务复制分发到订阅同步慢 最近发现有一个发布经常出现问题,每几天就出错不同步,提示要求初始化.重新调整同步后,复制还是很慢!每天白天未分发的命令就达五六百万条!要解决慢的问题,需要了解从发布数据库到订阅数据库中,有哪些操作,才知道哪个步骤同步缓慢. 这是很久之前自己做的一张图,主要描述发布到分发.分发到订阅中,复制使用了哪些操作,如下图: 发布到分发: 在发布中,复制是使用日志读取器读(sp_replcmds)取发布数据库中的事务日志的,日志读取器是按事务顺序读取的,

SQL Server事务回滚对自增键的影响

SQL Server事务回滚时是删除原先插入导致的自增值,也就是回滚之前你你插入一条数据导致自增键加1,回滚之后还是加1的状态 --如果获取当前操作最后插入的identity列的值:select @@IDENTITY--如果要获取某表的最后的identity列的值:select IDENT_CURRENT('表名') --如果要模拟抛出异常可以用RAISERROR --RAISERROR('错误的描述',错误的严重级别代码,错误的标识,错误的描述中的参数的值(这个可以是多个),一些其它参数) -