Does 'begin transaction' with label prevent rollback all nested procedures? - sql-server

If I have 3 procedures, one inside the other, I know that commit and rollback work like this:
If I put a label for each tansaction, does the rollback only rolls back to the previous procedure? like this:

From the SQL Server documentation:
ROLLBACK TRANSACTION without a savepoint_name or transaction_name rolls back to the beginning of the transaction. When nesting transactions, this same statement rolls back all inner transactions to the outermost BEGIN TRANSACTION statement. In both cases, ROLLBACK TRANSACTION decrements the ##TRANCOUNT system function to 0. ROLLBACK TRANSACTION savepoint_name does not decrement ##TRANCOUNT.
Note the part I've emphasised. Unless you specify the name of an outer transaction, a rollback will only affect the innermost transaction.

Related

How Outer Transaction query should not effect when Inner Transaction fails

I have a scenario where my Inner Transaction is failing by a condition not by syntax error so outer transaction should not effect.
Is there a way to achieve this.
The concept of INNER or OUTER transaction does not exists...
Just have a look at the definition of what is a transaction :
en.wikipedia.org-wiki/Database_transaction
"A database transaction, by definition, must be atomic"
So, can we have subatomic process in an atomic process ? Of course not !
I must say that the concept of transaction is better understood when you think at the session level... A session can be in an explicit transaction state or not.
Any subtransaction is only an artefact needed because you can call a procedure which has its own transaction, that call another procedure that have also its own transaction... The accumulation of BEGIN TRANSACTION ha no effect on the transaction state, this only increments the ##TRANCOUT counter.
The frontier of a transactional state are
BEGIN TRANSACTION as the entry point
COMMIT or ROLLBACK at the exit point
When the session is not in the transactional state, ##TRANCOUT is valued to 0.
WHen BEGIN TRANSACTION is executed the ##TRANCOUT is incremented to one
WHEN COMMIT is executed the ##TRANCOUT is decremented to one:
if the value decrease to 0, the COMMIT will effectively do a COMMIT
if the value is > 0, nothing happen
When a ROLLBACK is executed, the ##TRANCOUT is immediately valued to 0 and the ROLLBACK is executed
That is why this nested concept of transaction, in this case (MS SQL Server) is called asymetric model...
You should have into your code either a test for ##TRANCOUNT or a TRY/CATCH and a test with the XACT_STATE() function to proper code the traitement

Stored procedure with multiple updates, insert and deletes. What happens if last DML command fails?

So, if I have multiple DML commands inside a stored procedure in SQL Server, if the last one fails, will all the other ones rollback? Considering I am not inside a transaction scope!
You need your stored procedure to use TRY CATCH and a TRANSACTION .
BEGIN TRAN
BEGIN TRY
COMMIT TRANSACTION
END TRY
BEGIN CATCH
-- if error, roll back any changes done by any of the SQL statements
ROLLBACK TRANSACTION
END CATCH
Refer to this
http://techfunda.com/howto/192/transaction-in-stored-procedure

How do I use transactions over multiple stored procedures?

Can you start a transaction in one stored procedure and then roll it back or commit it in a nested procedure?
Commit and rollback have different effects
COMMIT decrements ##TRANCOUNT
ROLLBACK pushes it back to zero
This happens because SQL Server does not really support nested transactions.
If you commit or rollback in a nested stored proc (not transaction), then you'll generate error 266 because of a ##TRANCOUNT mismatch on start and entry
The rollback issue can be resolved by using SET XACT_ABORT ON which is "auto rollback" (simply) and suppresses error 266.
The commit issue... you can't as such. However, you can control where it happens by noting ##TRANCOUNT on stored proc entry and committing only if zero.
For correct transaction handling, see my answers here please:
Nested stored procedures containing TRY CATCH ROLLBACK pattern? and Have I to count transactions before rollback one in catch block in T-SQL?
You can't commit it in a nested procedure, but starting a transaction will wrap all nested procedures within it. So the transaction is good for all stored procedures nested within the transaction. In distributed transactions, data integrity even crosses machine boundaries.
http://msdn.microsoft.com/en-us/library/ms188929(v=SQL.90).aspx
You should pair up your BEGIN TRAN and COMMITs in the same SPROC
If you then call another SPROC which also has a transaction, subsequent BEGIN TRAN / COMMIT TRAN pairs will increment and decrement ##Trancount respectively.
The transaction is committed on the 'last' COMMIT TRAN (##Trancount = 1)
However, any ROLLBACK will always roll back the transaction.
MSDN has a good explanation.
Yes, it is possible. With programming languages like C#, when you pass the connection and transaction object with the command. if anything is caught as wrong than rollback the transaction:
string customerConnection = "Connection";
string query = "insert into temp values ('Data2','data1','data2','data3')";
string query2 = "update tempcst set data = 'Hello data'";
SqlConnection myConnection = new SqlConnection(customerConnection);
myConnection.Open();
SqlTransaction myTrans = myConnection.BeginTransaction();
Try{
int result = executeNonQuery(query, myConnection, myTrans, "");
i = executeNonQuery(query2, myConnection, myTrans, "");
myTrans.Commit();}
catch{
myTrans.Rollback();
myConnection.Close();
}

How can I ensure that nested transactions are committed independently of each other?

If I have a stored procedure that executes another stored procedure several times with different arguments, is it possible to have each of these calls commit independently of the others?
In other words, if the first two executions of the nested procedure succeed, but the third one fails, is it possible to preserve the results of the first two executions (and not roll them back)?
I have a stored procedure defined something like this in SQL Server 2000:
CREATE PROCEDURE toplevel_proc ..
AS
BEGIN
...
while #row_count <= #max_rows
begin
select #parameter ... where rownum = #row_count
exec nested_proc #parameter
select #row_count = #row_count + 1
end
END
First off, there is no such thing as a nested transaction in SQL Server
However, you can use SAVEPOINTs as per this example (too long to reproduce here sorry) from fellow SO user Remus Rusanu
Edit: AlexKuznetsov mentioned (he deleted his answer though) that this won't work if a transaction is doomed. This can happen with SET XACT_ABORT ON or some trigger errors.
From BOL:
ROLLBACK TRANSACTION without a
savepoint_name or transaction_name
rolls back to the beginning of the
transaction. When nesting
transactions, this same statement
rolls back all inner transactions to
the outermost BEGIN TRANSACTION
statement.
I also found the following from another thread here:
Be aware that SQL Server transactions
aren't really nested in the way you
might think. Once an explict
transaction is started, a subsequent
BEGIN TRAN increments ##TRANCOUNT
while a COMMIT decrements the value.
The entire outmost transaction is
committed when a COMMIT results in a
zero ##TRANCOUNT. But a ROLLBACK
without a savepoint rolls back all
work including the outermost
transaction.
If you need nested transaction
behavior, you'll need to use SAVE
TRANSACTION instead of BEGIN TRAN and
use ROLLBACK TRAN [savepoint_name]
instead of ROLLBACK TRAN.
So it would appear possible.

Properly scoped transactions in Stored Procs

Suppose I have a stored procedure that manages its own transaction
CREATE PROCEDURE theProc
AS
BEGIN
BEGIN TRANSACTION
-- do some stuff
IF #ThereIsAProblem
ROLLBACK TRANSACTION
ELSE
COMMIT TRANSACTION
END
If I call this proc from an existing transaction, the proc can ROLLBACK the external transaction.
BEGIN TRANSACTION
EXEC theProc
COMMIT TRANSACTION
How do I properly scope the transaction within the stored procedure, so that the stored procedure does not rollback external transactions?
The syntax to do this probably varies by database. But in Transact-SQL what you do is check ##TRANCOUNT to see if you are in a transaction. If you are then you want to create a savepoint, and at the end you can just pass through the end of the function (believing a commit or rollback will happen later) or else rollback to your savepoint.
See Microsoft's documentation on savepoints for more.
Support for savepoints is fairly widespread, but I think the mechanism (assuming there is one) for finding out that you're currently in a transaction will vary quite a bit.
use ##trancount to see if you're already in a transaction when entering

Resources