存储过程调用中事务嵌套时发生回滚时,如何控制回滚到上一级而不是最外层事务?

fredfei 2002-04-11 04:02:31
我有几个存储过程作如下定义:

create procedure test1
@ret int output
as
set @ret=-1
begin tran in_test
insert.....
if @@error<>0
roolback tran in_test
else
begin
set @ret=0
commit tran in_test
end
------------------------------
create procedure test2
as
declare @outvalue
set @outvalue=0
begin tran out_test
exec test1 @ret=@outvalue
if ....
else ....
.......
exec ... -------其他类似test1结构的存储过程,其中有的还嵌套存储过程
....
if @outvalue=0
commit tran out_test
else
roolback tran out_test
----------------------------------------------------
目的:
我用@outvalue来传递是否正常结束,一旦有一个存储过程执行过程发生问题,则全部回滚
条件:
1.回答时全部@outvalue值变化的逻辑关系不考虑,仅考虑事务
2.由于test1要单独使用,因此必须使用事务
3.不要解释错误内容,我知道

问题:
当存储过程test1发生回滚时,会报错

服务器: 消息 6401,级别 16,状态 1,过程 test1,行 xx
无法回滚 in_test。没有找到任何该名称的事务或保存点。
服务器: 消息 266,级别 16,状态 2,过程 test1,行 xxx
EXECUTE 后的事务计数指出缺少了 COMMIT 或 ROLLBACK TRANSACTION 语句。原计数 = 1,当前计数 = 2。

请问如何控制事务使其在回滚后保证EXECUTE 后的事务计数正常
...全文
579 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
fredfei 2002-04-15
  • 打赏
  • 举报
回复
我其實是想研究一下commit和rollback在exec後的變化情況及原因,
lyxinfo的方法我知道,不過我仍然非常感謝你
同時也感謝其他跟帖的朋友

結分
lyxinfo 2002-04-12
  • 打赏
  • 举报
回复
ROLLBACK 保存点,是不会修改 @@trancount的。可以试一试。

我那样写,如果发生嵌套调用,事务的提交只能在最外层进行,内层不再创建新的事务,而是通过保存点来实现回滚。一旦@@trancount大于1,不要指望还可以回滚到等于1的状态。
各个语句对@@trancount的影响:
begin tran @@trancount = @@trancount + 1
commit tran @@trancount = @@trancount - 1
rollback tran @@trancount = 0
save tran 不变
rollback save point 不变

就事务处理而言,我写的那个是一个标准的解决方法(也许还有其他)。
leimin 2002-04-12
  • 打赏
  • 举报
回复
同意楼上的意见,所以么设置一变量来保存@@TRANCOUNT,判断嵌套的层数,

wylyf 2002-04-12
  • 打赏
  • 举报
回复
看来你应该在第一个存储过程中再加一个参数,来判断是独立调用还是嵌套调用了!如果是嵌套调用那么就用ROLLBACK TRANSACTION OutTrans 来回滚所有事务
wylyf 2002-04-12
  • 打赏
  • 举报
回复
ROLLBACK TRANSACTION 语句的 transaction_name 参数引用一组命名的嵌套事务的内层事务是非法的,transaction_name 只能引用最外部事务的事务名。如果在一组嵌套事务的任意级别执行使用外部事务名称的 ROLLBACK TRANSACTION transaction_name 语句,那么所有的嵌套事务都将回滚。如果在一组嵌套事务的任意级别执行没有 transaction_name 参数的 ROLLBACK WORK 或 ROLLBACK TRANSACTION 语句,那么它将回滚所有嵌套事务,包括最外部事务。

这是联机丛书上说的,就是说你应该在ROLLBACK的时候只能指定一个ROLLBACK TRANSACTION TRANS_NAME 而在内层无法使用ROLLBACK TRANSACTION TRANS_NAME 。这就是我的理解。而你再第一个存储过程中ROLLBACK TRANSACTION TRANSNAME 就会报错!
wylyf 2002-04-12
  • 打赏
  • 举报
回复
关注:
不过我不明白一点,
你这个@OutValue是如何来保证所有的事务都正确执行?
Exec Test1 @reg=@OutValue 返回0
Exec Test1 @reg=@OutValue 返回-1
Exec Test1 @reg=@OutValue 返回0
其中有一次没有正确执行,你如何判断呢?
lyxinfo 2002-04-12
  • 打赏
  • 举报
回复
哦,漏了,这里也要判断一下,保存点不要再commit了
if @@error<>0
begin
rollback tran p1 /*此处修改*/
else
if @trncnt = 0
begin
set @ret=0
commit tran p1
end
blackhawk_yps 2002-04-12
  • 打赏
  • 举报
回复
在事务 发生Rollback后,用return 退出存储过程。
lyxinfo 2002-04-12
  • 打赏
  • 举报
回复
写的有些错误,原来的事务处理没有去掉。
create procedure test1
@ret int output
as

/*增加部分,处理事务嵌套*/
declare
@trncnt int /*事务记数*/
select @trncnt = @@trancount
if @trncnt = 0 /*判断事务记数,根据情况确定使用保存点或者新建一个事务*/
begin tran p1
else
save tran p1
/*增加部分结束*/

set @ret=-1
--begin tran in_test
insert.....


if @@error<>0
begin
rollback tran p1 /*此处修改*/
else
begin
set @ret=0
commit tran p1
end
return
lyxinfo 2002-04-11
  • 打赏
  • 举报
回复
标准方案,但是没有测试,试一试。
定义被调用存储过程
create procedure test1
@ret int output
as

/*增加部分,处理事务嵌套*/
declare
@trncnt int /*事务记数*/
select @trncnt = @@trancount
if @trncnt = 0 /*判断事务记数,根据情况确定使用保存点或者新建一个事务*/
begin tran p1
else
save tran p1
/*增加部分结束*/

set @ret=-1
begin tran in_test
insert.....


if @@error<>0
begin
set @ret = -1 /*返回错误*/
rollback tran p1 /*此处修改*/
else
begin
set @ret=0
commit tran

return

调用的存储过程
/*这里如果没有再被嵌套,就不用改了,否则可以类似上边的处理方式*/
create procedure test2
as
declare @outvalue
set @outvalue=0
begin tran out_test
exec test1 @ret=@outvalue

if ....
else ....
.......
exec ... -------其他类似test1结构的存储过程,其中有的还嵌套存储过程
....
if @outvalue=0
commit tran out_test
else
rollback tran out_test
leimin 2002-04-11
  • 打赏
  • 举报
回复
在test1中不需要break point
fredfei 2002-04-11
  • 打赏
  • 举报
回复
高手都哪去了?
fredfei 2002-04-11
  • 打赏
  • 举报
回复
加分!

请大家看清题目要求,同时要考虑以下几种情况
1。独立应用test1正常提交
2。独立应用test1回滚
3。嵌套使用test1正常提交
4。嵌套使用test1回滚
这4种情况均不能出错
fredfei 2002-04-11
  • 打赏
  • 举报
回复
我忘了说明了,在test1中
如果用
save transaction in_test
那么提交后
commit tran in_test
同样会报错
leimin 2002-04-11
  • 打赏
  • 举报
回复
忘记提醒您:
嵌套存储过程中,要非常注意ROLLBACK TRANSACTION
最好加一个语句

IF @@TRANCOUNT>O

RILLBACK TRANSACTION
leimin 2002-04-11
  • 打赏
  • 举报
回复
是否可以设置一个保存点

create procedure test2
as
declare @outvalue
set @outvalue=0
begin tran out_test
SAVE TRANSACTION @POINT1
exec test1 @ret=@outvalue
if @ERROR<>0
ROLLBACK TRANSACTION @POINT1
RETURN @ERROR
else ....
.......
exec ... -------其他类似test1结构的存储过程,其中有的还嵌套存储过程
....
if @outvalue=0
commit tran out_test
else
roolback tran out_test
tiggle 2002-04-11
  • 打赏
  • 举报
回复
语法应该是
save transaction tran_name
tiggle 2002-04-11
  • 打赏
  • 举报
回复
如果要让事务回滚到指定的位置需要在事务中设定Save Point point_name.

34,591

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧