在云那方

首页 新随笔 联系 订阅 管理

详细的出错信息:

EXECUTE 后的事务计数指出缺少了 COMMIT 或 ROLLBACK TRANSACTION 语句。原计数 = 0,当前计数 = 1。

这是我错误的存储过程,在这个存储过程里,我想做的是开始一个事务,设置这个事务的保存点,更新库存,如果库存更新失败,或者没有符合条件的数据行被更新,就返回出错,否则,添加提货单,如果提货单添加时出错,同样返回到一开始设置的保存点,否则,我就返回成功的信息

create proc a_stationery_useAdd ( @return int out, @rid int, @eid int, @trueName varchar(30), @num int, @useDay smalldatetime, @operatorEid int, @operatorTrueName varchar(30), @uid int, @una varchar(30), @remark varchar(400) ) as

begin transaction trn_useAdd
save transaction stk_useAdd

--update stock
update T_stationery_stock
   set stocks = stocks - @num
 where rid = @rid and ( stocks > @num or stocks = @num )
if @@error<>0 or @@rowcount = 0
   begin
     select @return = -2
     raiserror('办公用品无效,或者库存量小于领用数量', 16 ,1)
     rollback transaction stk_useAdd
     return

   end

--add bill of lading
insert into T_stationery_billLading
  ( rid, eid, trueName, num, useDay, operatorEid, operatorTrueName, uid, una, createTime, remark )
values
  ( @rid, @eid, @trueName, @num, @useDay, @operatorEid, @operatorTrueName, @uid, @una, getdate(), @remark )
if @@error<>0 or @@rowcount = 0
   begin
     select @return = -3
     rollback transaction stk_useAdd
     return
   end

select @return = 1
commit transaction

分析上面的代码,可以发现两个错误的地方

1、save transaction stk_useAdd设置在事务一开始的时候,这个不是错误,就是这样的设置是重复的,没有用的,因为

BEGIN TRANSACTION 代表一点,由连接引用的数据在该点是逻辑和物理上都一致的。如果遇上错误,在 BEGIN TRANSACTION 之后的所有数据改动都能进行回滚,以将数据返回到已知的一致状态。每个事务继续执行直到它无误地完成并且用 COMMIT TRANSACTION 对数据库作永久的改动,或者遇上错误并且用 ROLLBACK TRANSACTION 语句擦除所有改动。

begin transaction trn_useAdd
save transaction stk_useAdd

这样的连续两个语句,使stk_useAdd和trn_useAdd都是保存在同一个状态下,这两个保存点,是完全一样的,所以没有必要在一开始的时候设置保存点

2、就是sql给出的出错信息“EXECUTE 后的事务计数指出缺少了 COMMIT 或 ROLLBACK TRANSACTION 语句。原计数 = 0,当前计数 = 1。”

这个出错信息是因为我没有很好的理解事务和保存点的关系,保存点是在事务内部的

不带 savepoint_name 和 transaction_name 的 ROLLBACK TRANSACTION 回滚到事务的起点。嵌套事务时,该语句将所有内层事务回滚到最远的 BEGIN TRANSACTION 语句。在这两种情况下,ROLLBACK TRANSACTION 均将 @@TRANCOUNT 系统函数减为 0。ROLLBACK TRANSACTION savepoint_name 不减少 @@TRANCOUNT。

ROLLBACK TRANSACTION 语句若指定 savepoint_name 则不释放任何锁。

在存储过程中,ROLLBACK TRANSACTION 语句不影响调用该过程的批处理中的后续语句;将执行批处理中的后续语句。在触发器中,ROLLBACK TRANSACTION 语句终止含有激发触发器的语句的批处理;不执行批处理中的后续语句。
智() 12:02:49 你对save的点做回滚后提交不会影响整个事务

就是说,我在trn_useAdd事务里,设置了一个保存点stk_useAdd,在执行出错的时候,我把数据rollback到stk_useAdd,就是stk_useAdd是在事务内部的,事务trn_useAdd本身,并没有被提交,也没有被回滚,所以@@TRANCOUNT不会清零,由trn_useAdd造成的锁,也不会被解锁

所以,如果是在事务里rollback到一个保存点,后return,就需要在return前提交或者回滚事务

看下面这一段,我把保存点设置在事务运行的中间,这种形式的保存点,和返回才是正确的

begin transaction trn_example

update tableName set fieldName = @value

save transaction stk_savePoint

update tableName2 set fieldName2 = @value2
if @@error<>0
   begin
     rollback transaction stk_savePoint
     commit transaction
     return
   end
else
   begin
     if @@rowcount = 0
        rollback transaction
   end

commit transaction

如果第二个update出现错误,就返回到第一个update后提交,并且使用return截断后面的语句继续运行

如果第二个update正确执行,就是更新的行数是0,就回滚整个事务,把第一个update执行的结果也取消

posted on 2008-07-04 12:10  Rich.T  阅读(2008)  评论(0编辑  收藏  举报