| Author |
Topic |
|
ilimax
Posting Yak Master
164 Posts |
Posted - 2010-01-08 : 14:21:23
|
| I have situation as thisCREATE PROCEDURE Run_All AS BEGIN BEGIN TRY BEGIN TRANSACTION EXEC PROCEDURE1 EXEC PROCEDURE2 EXEC PROCEDURE3 COMMIT TRANSACTION END TRY BEGIN CATCH RAISERROR ROLLBACK TRANSACTION END CATCHENDIn PROCEDURE1, PROCEDURE2 AND PROCEDURE3 there is BEGIN TRY and ROLLBACK in CATCH block. These 3 procedures have looked almost identical with constcrutcion as this Run_All procedure. Here is PROCEDURE1 ...CREATE PROCEDURE PROCEDURE1 ASBEGIN BEGIN TRY BEGIN TRANSACTION SQL statements COMMIT TRANSACTION SET IDENTITY_INSERT TableInsertTo OFF END TRY BEGIN CATCH RAISERROR ROLLBACK TRANSACTION END CATCHENDSo, they call 3 procedures from one procedure where they set ROLLBACK in CATCH block.My question is, if error happend in PROCEDURE3, is it going to ROLLBACK results from PROCEDURE1 and PROCEDURE2 even they run good (these 2 procedures have COMMIT TRANSACTION line)Thanks,Ilimax |
|
|
tkizer
Almighty SQL Goddess
38200 Posts |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2010-01-08 : 15:00:24
|
Gonna have to disagree there. The way you have it written, where Run_All has a transaction and all three inner procs have a (nested) transaction, with no save points, a rollback anywhere will roll back everything. Notice here that the @@trancounts from proc3 before and after the rollback go from 2 to 0. And that the final output of Select * from Junk shows the original value for [i] of "0". So the inner proc3 rollback rolled back the changes from run_all, proc1, and proc2.use tempdbgocreate table junk (i int)goinsert junk (i) values (0)gocreate proc PROCEDURE1asbegin tranbegin try update junk set i = 1 commit tranend trybegin catch rollback tranend catchgocreate proc PROCEDURE2asbegin tranbegin try update junk set i = 2 commit tranend trybegin catch rollback tranend catchgocreate proc PROCEDURE3asbegin tranbegin try update junk set i = 3 --force an error raiserror('forced error in proc3', 17, 1)end trybegin catch select @@trancount [Proc3: trancount before rollback] rollback tran select @@trancount [Proc3: trancount after rollback]end catchgoCREATE PROCEDURE Run_All ASBEGIN BEGIN TRANSACTION BEGIN TRY --parent update update junk set i = -1 EXEC PROCEDURE1 EXEC PROCEDURE2 EXEC PROCEDURE3 COMMIT TRANSACTION END TRY BEGIN CATCH select @@trancount [trancount from run_all] if @@trancount > 0 ROLLBACK TRANSACTION RAISERROR('error from Run_All', 17, 1) END CATCHENDgoexec Run_Allgoselect * from junkgodrop proc Run_Alldrop proc PROCEDURE1drop proc PROCEDURE2drop proc PROCEDURE3drop table junkOUTPUT:(1 row(s) affected)(1 row(s) affected)(1 row(s) affected)(1 row(s) affected)(1 row(s) affected)Proc3: trancount before rollback--------------------------------2(1 row(s) affected)Proc3: trancount after rollback-------------------------------0(1 row(s) affected)trancount from run_all----------------------0(1 row(s) affected)Msg 50000, Level 17, State 1, Procedure Run_All, Line 16error from Run_Alli-----------0(1 row(s) affected)Be One with the OptimizerTG |
 |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2010-01-08 : 15:04:57
|
| I prefer to use a single transaction in the calling procedure. Either have your inner catch blocks return a RETURN code to the caller to OR raise an error in the inner catch block to force the caller to go to it's catch block. But in either case a single controlling transaction is much less confusing.Be One with the OptimizerTG |
 |
|
|
ilimax
Posting Yak Master
164 Posts |
Posted - 2010-01-08 : 15:15:43
|
| Thanks TG |
 |
|
|
tkizer
Almighty SQL Goddess
38200 Posts |
|
|
denis_the_thief
Aged Yak Warrior
596 Posts |
Posted - 2011-03-02 : 12:10:05
|
I am still stuck on this. We have to be 2000-compatible so we can't use the try-catch. Without the try-catch, is there anyway to avoid the 'Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements' error?We need a begin tran/rollback/commit for the Parent Stored Proc. Plus we need a begin tran/rollback/commit for the Child Stored Proc since it could be called either on its own or from the Parent. It seems no matter what, we will get the mismatch error if there is a rollback in the Child since before calling the Child, Trancount will be 1 and after returning from the child, Trancount will be 0. Any ideas?CREATE PROCEDURE dbo.p1AS BEGIN TRAN EXEC dbo.p2; if @@Trancount = 1 COMMIT TRAN;GOCREATE PROCEDURE dbo.p2ASbegin tran select 1/0 if @@Error <> 0 begin ROLLBACK TRAN --begin tranendGOEXEC dbo.p1;drop procedure p1drop procedure p2 Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0. |
 |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2011-03-04 : 16:38:42
|
The best way is to find a way not to nest transactions. Either combine the SPs or re-evaluate if you really need a transaction on the inner proc. But if you absolutely have to do it this way:In 2000 you can use CONTEXT_INFO to set a "message" for any other code that is in the context of the calling SPID. So you set the value in the p1 and check it in p2. Conditionally start a transaction only if you're not already in one.CREATE PROCEDURE dbo.p1AS BEGIN TRAN declare @InTran varbinary(128) select @inTran = convert(varbinary(128), 'In Tran from p1') set context_info @InTran EXEC dbo.p2; if @@Trancount > 0 COMMIT TRAN;GOCREATE PROCEDURE dbo.p2ASselect @@trancount [trancount beginngin of p2]--check the transaction state. declare @TranState varchar(128)select @TranState = convert(varchar(128), context_info)from sys.sysprocesses where spid = @@spidselect @TranState [TranState]if isNull(@TranState,'') not like 'In Tran from p1%' begin tranelse print 'no nested transaction'select @@trancount [trancount middle of p2]--generate an errorselect 1/0if @@Error <> 0 begin print 'error' if isNull(@TranState,'') not like 'In Tran from p1%' rollback tranend if isNull(@TranState,'') not like 'In Tran from p1%' commit select @@trancount [trancount end of p2]goEXEC dbo.p1exec dbo.p2godrop procedure p1drop procedure p2 Be One with the OptimizerTG |
 |
|
|
denis_the_thief
Aged Yak Warrior
596 Posts |
Posted - 2011-03-09 : 08:46:51
|
Thankyou TG.I'm trying a way that is similar. I hope it will work?declare @InitialTranCount int select @InitialTranCount = @@TranCountif @InitialTranCount = 0 BEGIN TRAN...if @InitialTranCount = 0 COMMIT TRAN... |
 |
|
|
|