I wondered if SQL Server supports nested transactions?
I can see other questions similar.
Also - How do I know if I am in a nested transaction?
This may seem a strange question .. but ..
in SSMS I might have run the command BEGIN TRANSACTION more than once by accident .. for example .. Will this mean that I need to run the COMMIT TRANSACTION more than once to finalise the transaction?
I'm thinking nested transactions should generally be avoided.
SELECT
[Initial Assess - Sweating],
COUNT(*)
FROM
Clinical.SAASCaseCards
GROUP BY
[Initial Assess - Sweating]
BEGIN TRANSACTION;
UPDATE Clinical.SAASCaseCards
SET [Initial Assess - Sweating] = '1'
WHERE [Initial Assess - Sweating]= '01'
COMMIT TRANSACTION ;
You can use the global variable ##TRANCOUNT to see how this works.
If you run select ##TRANCOUNT and you have no transactions around you will get 0.
Each time begin transaction is run, ##TRANCOUNT increases by 1.
Each time commit (transaction) is run, ##TRANCOUNT decreases by 1. If that made ##TRANCOUNT to be set to 0, then the transaction(s) are indeed committed.
On the other hand, a rollback (transaction) will set ##TRANCOUNT to 0 and roll back all changes regardless of the value of ##TRANCOUNT at that time.
So, there is no functional nesting. There is only this counter in order to allow different modules to make their own transaction handling.
I recommend Erland Sommerskog's article for further reading.
Yes transaction can be nested. But once your outer transaction fails, your inner transaction will be rollback too.
Nested transactions in Sql Server
So far as I am aware, transactions cannot be nested.
Related
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
This question already has answers here:
What happens if you don't commit a transaction to a database (say, SQL Server)?
(10 answers)
Closed 9 years ago.
If I Enclose a query between Begin Transaction and commit transaction in MS SQL, what will happen if i abort or stop the execution of the query. Will all the changes that had been done during executing ROLLBACKED.?
Your transaction can remain open until you call something like ROLLBACK TRANSACTION or COMMIT TRANSACTION, or until SQL takes some action on it.
More info:
SQL Server and connection loss in the middle of a transaction
What happens to an uncommitted transaction when the connection is closed?
What happens if you don't commit transaction in a database (say SQL Server)
I actually like to take advantage of this when testing large updates or corrections. You can have something like this:
-- BEGIN TRANSACTION
-- ROLLBACK TRANSACTION
-- COMMIT TRANSACTION
/*
A bunch of SQL code here
*/
Then you can highlight/run the BEGIN TRANSACTION, then run the whole script. If you're happy with the results, you can highlight/run the COMMIT TRANSACTION. If not, run the ROLLBACK TRANSACTION. Since those lines are commented out, they don't affect your overall transaction unless you explicitly highlight and run them.
It depends on your code. As long as your transaction exist, all changes will be pending a rollback or a commit.
You might want to look at this.
No. Transaction will still be active - you didn't rollback after all, did you? :)
Run this example and see what happens. If you break during transaction, you'll see value 2 is in a table, but you have to rollback or commit.
select 1 as x into #xxx
GO
begin transaction
insert into #xxx(x) select 2
-- ctrl+break before time runs out.
waitfor delay '00:00:10'
commit transaction
-- now try this:
select * from #xxx
rollback transaction
select * from #xxx
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();
}
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.
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