您的位置:首页 > 博客中心 > 数据库 >

SQL Server——事务嵌套

时间:2022-03-13 23:32

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,中间人为触发一些错误,然后观察运行结果。

 

 

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


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

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

 

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

热门排行

今日推荐

热门手游