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

 
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执行的结果也取消

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关于mysql的事务处理 public static void StartTransaction(Connection con, String[] sqls) throws Exception { if (sqls == null) { return; } Statement sm = null; try { // 事务开始 System.out.println("事务处理开始!"); con.setAutoCommit(false); // 设置连接不自动提交,即用该连接进行的操作都不更新到数据库 sm = con.createStatement(); // 创建Statement对象 //依次执行传入的SQL语句 for (int i = 0; i < sqls.length; i++) { sm.execute(sqls[i]);// 执行添加事物的语句 } System.out.println("提交事务处理!"); con.commit(); // 提交给数据库处理 System.out.println("事务处理结束!"); // 事务结束 //捕获执行SQL语句组中的异常 } catch (SQLException e) { try { System.out.println("事务执行失败,进行回滚!\n"); con.rollback(); // 若前面某条语句出现异常时,进行回滚,取消前面执行的所有操作 } catch (SQLException e1) { e1.printStackTrace(); } } finally { sm.close(); } } 通常都是上述的写法, 在mysql 不支持事务的时候 , 中间的 setAutoCommit事务操作是不是都不生效. 现在innoDB支持 事务了, 上述的 java 代码是否能实现 以下的 事务隔离的 操作, 在修改的时候处于锁定状态 或者 只可以通过存储过程来实现, 单行的锁定 BEGIN; SELECT book_number FROM book WHERE book_id = 123 FOR UPDATE; --这里for update , 以前用Oracle的时候也是有这个行锁 // ... UPDATE book SET book_number = book_number - 1 WHERE book_id = 123; COMMIT;

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值