CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Darrell Norton's Blog [MVP]

Fill in description here...

SQL Server Transactions - Commit and Rollback

A coworker was having trouble with a stored proc. There were several IF statements where one path created another nested level transaction while the other did not. Trying to get the stored proc to COMMIT only certain transactions by name was sometimes generating an error that there was no corresponding BEGIN TRANSACTION. What we learned was the following.

Whenever you execute a COMMIT TRANSACTION statement, any transaction name after the statement is ignored. The only thing a COMMIT TRANSACTION statement does is reduce the @@trancount variable by 1. If this makes @@trancount = 0, then all database modifications are committed.

For example, say you have the following code (from SQL Server Books Online):

CREATE TABLE TestTran (Cola INT PRIMARY KEY, Colb CHAR(3))
GO
BEGIN TRANSACTION OuterTran -- @@TRANCOUNT set to 1.
GO
INSERT INTO TestTran VALUES (1, 'aaa')
GO
BEGIN TRANSACTION Inner1 -- @@TRANCOUNT set to 2.
GO
INSERT INTO TestTran VALUES (2, 'bbb')
GO
BEGIN TRANSACTION Inner2 -- @@TRANCOUNT set to 3.
GO
INSERT INTO TestTran VALUES (3, 'ccc')
GO
COMMIT TRANSACTION Inner2 -- Decrements @@TRANCOUNT to 2.
-- Nothing committed.
-- ROLLBACK TRANSACTION Inner1
GO
COMMIT TRANSACTION Inner1 -- Decrements @@TRANCOUNT to 1.
-- Nothing committed.
GO
COMMIT TRANSACTION OuterTran -- Decrements @@TRANCOUNT to 0.
-- Commits outer transaction OuterTran.
GO
DROP TABLE TestTran

Just copy and paste this code into Query Analyzer.  Add Select statements wherever you would like to see the state of the TestTran table and whether the statements have been committed or not.

The only transaction name that SQL Server cares about is OuterTran. It’s fine to label Inner1 and Inner2 transactions for other developers, but SQL Server does not use them. Also, the COMMIT TRANSACTION statement does not use the transaction name. Only a ROLLBACK uses the transaction name, and only the outermost transaction name. For example, trying to do ROLLBACK TRANSACTION Inner1 where it is commented out in the code snippet above would not work.

UPDATE: From BOL, thanks to Frans for pointing this out to me.  It makes intuitive sense, and is the confirmed behavior.

Committing inner transactions is ignored by Microsoft® SQL Server™. The transaction is either committed or rolled back based on the action taken at the end of the outermost transaction. If the outer transaction is committed, the inner nested transactions are also committed. If the outer transaction is rolled back, then all inner transactions are also rolled back, regardless of whether or not the inner transactions were individually committed.

Each call to COMMIT TRANSACTION or COMMIT WORK applies to the last executed BEGIN TRANSACTION. If the BEGIN TRANSACTION statements are nested, then a COMMIT statement applies only to the last nested transaction, which is the innermost transaction. Even if a COMMIT TRANSACTION transaction_name statement within a nested transaction refers to the transaction name of the outer transaction, the commit applies only to the innermost transaction.

It is not legal for the transaction_name parameter of a ROLLBACK TRANSACTION statement to refer to the inner transactions of a set of named nested transactions. transaction_name can refer only to the transaction name of the outermost transaction. If a ROLLBACK TRANSACTION transaction_name statement using the name of the outer transaction is executed at any level of a set of nested transactions, all the nested transactions are rolled back. If a ROLLBACK WORK or ROLLBACK TRANSACTION statement without a transaction_name parameter is executed at any level of a set of nested transaction, it rolls back all the nested transactions, including the outermost transaction.



Comments

Darrell said:

In-ter-esting! I looked up nested transactions in BOL, and that's the case. I will update the post with this info.
# December 24, 2003 1:45 AM

Jason said:

So then are you saying that a stored procedure wrapped in a transaction can be used standalone, but cannot be used as part of another stored procedure that is also wrapped in a transaction?

For Example: I have a sp, "CreateUserFolder", which creates a "folder" table entry and creates a "folderstorage" table entry to assign it to a user. These 2 inserts within this sp are wrapped within a transaction.

I also have a "CreateMembership" sp, which creates a new user ("member" table entry). I also want to create 2 default folders for this user upon creation, so I make 2 calls to the existing sp "CreateUserFolder" mentioned above. However, since the CreateMembership sp is also wrapped in a transaction, if I issue a rollback within the sp "CreateUserFolder", it throws my @@TRANCOUNT back to 0 and when it returns to the calling procedure, it give me this error: Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0.

Now, I could remove the transaction from "CreateUserFolder" but I want to be able to call this standalone, in which the Transaction is needed.

Is there any way around this?
# February 14, 2004 2:13 PM

Darrell said:

Jason -

If you ever issue a rollback, it rollsback the outermost transaction. That's because SQL Server only really has 1 transaction per connection (see Frans' comment above). If you want to rollback the entire transaction but are getting that error, wrap the COMMIT or ROLLBACK transaction statement in the "CreateMembership" proc that only issues the statement IF @@TRANCOUNT > 0.
# February 15, 2004 3:55 AM

PrasadMeduri said:

hi all,
Please send me some relevant information on the related issues. I need transaction control and datamanipulation utilities in sqlserver through .net framework.


thanks again
PrasadMeduri
# May 2, 2004 10:16 PM

Darrell said:

Prasad - see the MSDN documentation on ADO.NET.
# May 3, 2004 2:22 AM

Singh said:

Folks,

I am a newbie moving from Oracle to SQL Server 2000 and found this page very helpful. Please help me with a TRANSACTION issue that I am facing. I have about 10 million records that I need to move from one table (TEST1 with columns v11, N11) to another (TEST2 with columns V22, N22) in the same database. To avoid creating huge TRANSACTION LOGs, I want to move the records in batches of, say, 10000 records, i.e., I want to COMMIT TRANSACTION every 10000 records. I have written the following code. Can you please review and let me know if it is correct or not.

declare @v_counter int, @v_v1 varchar(50), @v_n1 int
set @v_counter = 0
declare c1 cursor for select v11, n11 from stg_test1
begin transaction
open c1
fetch next from c1 into @v_v1, @v_n1
while @@fetch_status = 0
begin
set @v_counter = @v_counter + 1
insert into stg_test2 (v22, n22) values (@v_v1, @v_n1)
if @v_counter%10000 = 0
begin
commit transaction
begin transaction
end
fetch next from c1 into @v_v1, @v_n1
end
commit transaction
close c1
deallocate c1

Thank you very much for the help!

Regards,

Singh
# June 22, 2004 9:17 AM

maxsekar said:

Hi

If you want to move data in SQL Server, you are better off using DTS wizard. Or if you still want to move the data using SQL Server, use Enterprise Manager to change the database properties -> make the logging option to "simple" and then do the operations. This will ensure that the db log does not overflow. You can always revert back to "Full" logging later.

Regards
Maxsekar
# September 2, 2004 10:36 PM

srinivas said:

Hi

how to roll back the dropped table in sql server?

pleaes send a solution for this becs this original data.

thanks in advance

bye now
seenu
# October 25, 2004 2:45 AM

srinivas said:

Hi

how to roll back the dropped table in sql server?

pleaes send a solution for this becs this original data.

thanks in advance

bye now
seenu
# October 25, 2004 2:45 AM

Darrell said:

Restore from backup. Or go through your transaction log.
# October 25, 2004 7:19 AM

Gabriel Lozano-Morn said:

Normally you can rollback a drop only when it is the only DDL statement in a transaction.
# February 10, 2005 1:36 AM
Check out Devlicio.us!

Our Sponsors