Committing Transaction - sql-server

http://msdn.microsoft.com/en-us/library/ms189797.aspx
In this link they are committing a transaction within catch clause IF (XACT_STATE()) = 1, I don't get it, if there is an error why they are committing it? even if the problem in select statement and there is no big deal committing it, why don't just roll it back.
Thanks

The link is demonstrating its use, that's all.
Saying that, it may be that in more complex code you want to do a partial commit, for example, rather than rolling back the entire transaction. However, you may not be able to (for example SET XACT_ABORT ON is used as per example)

It's just demonstration code to show that SET XACT_ABORT ON; makes it impossible to commit a transaction where an error occured.
As an example where you might want to commit a transaction after an error, consider logging code. You typically want the log entries to be committed when possible, even if the new order insert resulted in a primary key violation.

Related

Why or when would you set SET XACT_ABORT to OFF?

I know what XACT_ABORT is. There is a lot of info on why to set this to on. My question is why would someone set it to off? The point of a transaction is either everything is done or nothing is done. So why would someone set this to off? Why MS even choose off as the default is strange (The default for triggers is on and I know that).
After some digging I can only think of one decent reason as to why you would. That would be that you would want the transaction to continue processing regardless of any errors that are flagged. It might be that you want to deal with the errors later on rather than having the entire transaction rolled back.
There are also certain times when having XACT_ABORT isn't required for data modification statements but requirement is different to preference.
Source: MSDN

SQL Server Rolls back my transaction when using THROW

I have an INSERT trigger on one of my tables that issues a THROW when it finds a duplicate. Problem is my transactions seem to be implicitly rolled back at this point - this is a problem, I want to control when transactions are rolled back.
The issue can be re-created with this script:
CREATE TABLE xTable (
id int identity not null
)
go
create trigger xTrigger on xTable after insert as
print 'inserting...';
throw 1600000, 'blah', 1
go
begin tran
insert into xTable default values
rollback tran
go
drop table xTable
If you run the rollback tran - it will tell you there is no begin tran.
If i swap the THROW for a 'normal' exception (like SELECT 1/0) the transaction is not rolled back.
I have checked xact_abort flag - and it is off.
Using SQL Server 2012 and testing through SSMS
Any help appreciated, thanks.
EDIT
After reading the articles posted by #Dan Guzman, i came to the following conclusion/summary...
SQL Server automatically sets XACT_ABORT ON in triggers.
My example (above) does not illustrate my situation - In reality I'm creating an extended constraint using a trigger.
My use case was contrived, I was trying to test multiple situations in the SAME unit test (not a real world situation, and NOT good unit test practice).
My handling of the extended constraint check and throwing an error in the trigger is correct, however there is no real situation in which I would not want to rollback the transaction.
It can be useful to SET XACT_ABORT OFF inside a trigger for a particular case; but your transaction will still be undermined by general batch-aborting errors (like deadlocks).
Historical reasons aside, i don't agree with SQL Server's handling of this; just because there is no current situation in which you'd like to continue the transaction, does not mean such a situation may not arise.
I'd like to see one able to setup SQL Server to maintain the integrity of transactions, if your chosen architecture is to have transactions strictly managed at origin, i.e. "he alone who starts the transaction, must finish it". This, aside from usual fail-safes, e.g. if your code is never reached due to system failure etc.
THROW will terminate the batch when outside the scope of TRY/CATCH (https://msdn.microsoft.com/en-us/library/ee677615.aspx). The implication here is that no further processing of the batch takes place, including the statements following the insert. You'll need to either surround your INSERT with a TRY/CATCH or use RAISERROR instead of THROW.
T-SQL error handing is a rather large and complex topic. I suggest you peruse the series of error-handling articles by Erland Sommarskog: http://www.sommarskog.se/error_handling/Part1.html. Most relevant here is the topic Can I Prevent the Trigger from Rolling Back the Transaction? http://www.sommarskog.se/error_handling/Part3.html#Triggers. The take away from a best practices point of view is that triggers are not the right solution if you enforce business rules in a trigger without a rollback.

Scripting using a transaction

I have a question but I can never get a clear answer. Any stored
procedure that used a transaction that I have looked at up until my recent job always had a commit transaction + a roll back in case of error. However I have seen a lot of code
at my new job that just has a begin transaction and then a commit at the end with no roll back. I understand why you would use a transaction with a rollback but why would you want to begin a transaction with no roll back? Is it so when you run that code you want to lock the table up so no values can be changed why your code is updating? If so why would you not want the added security of a roll back in case something goes wrong? Is this proper use of the transaction statement? Any thoughts or ideas would be great!
For Example:
BEGIN TRANSACTION [Tran1]
INSERT INTO [Test].[dbo].[T1]
([Title], [AVG])
VALUES ('Tidd130', 130), ('Tidd230', 230)
UPDATE [Test].[dbo].[T1]
SET [Title] = N'az2' ,[AVG] = 1
WHERE [dbo].[T1].[Title] = N'az'
COMMIT TRANSACTION [Tran1]
GO
shouldn't this code be using a roll back syntax for proper use of the begin transaction statement?
The idea is that if that set of transactions needs to be "all or nothing", wrapping the lot in a transaction is the way to ensure that is what will happen. You're not seeing an explicit rollback because that's not what they're guarding against. Imagine the ff scenario with your contrived example:
The insert happens
The server crashes (or the log fills up or some other external reason why things can't continue) before the update can happen
If they're both wrapped in the same transaction, the insert won't be reflected in the table data. Which is the desired behavior.
When transactions are not explicitly declared, SQL Server will automatically BEGIN and COMMIT a TRANSACTION for each command. This frees up each command's lock as soon as the command executes.
When executing multiple commands inside a single transaction (as in the example you posted), locks from all commands are held until the transaction is committed.
Depending on the desired behavior, the script you posted may be correct. However, I would be cautious to ensure that the developer did not mistakenly believe that the transaction would be automatically rolled back on error. If that behavior is desired, you do indeed need to explicitly ROLLBACK or SET XACT_ABORT ON
You use transaction when you need the outcome to be atomic, you would see this alot in financial related procedures where you are gravely worried about data acid consistency . Otherwise it is not necessary and introduces a great deal of locking overhead. There is a good question here and here that goes into great depth.
Edit
The takeaway point is if the procedure is a all or none and must either succeed or fail the correct decision is to use a transaction. If the procedure is not a all or none transaction such as simple insert update etc using a transaction is a) unnecessary and b) can introduce an undue performance overhead due to additional locking.

How to roll back UPDATE statement?

Is this possible without restoring whole database?
I have made changes which I would like to undo, but without putting DB offline, and doing full restore.
No, SQL Server does not have Ctrl + Z.
You protect yourself from this scenario by wrapping all DML statements in a transaction. So you have query windows with this:
BEGIN TRANSACTION;
UDPATE ...
-- COMMIT TRANSACTION;
-- ROLLBACK TRANSACTION;
When you run the update, verify that you updated the right number of rows, the right rows, the right way, etc. And then highlight either the commit or the rollback, depending on whether you performed the update correctly.
On the flip side, be careful with this, as it can mess you up the other way - begin a transaction, forget to commit or rollback, then go out for lunch, leave for the day, go on vacation, etc.
Unfortunately that will only help you going forward. In your current scenario, your easiest path is going to be to restore a copy of the database, and harvest the data from that copy (you don't need to completely over-write the current database to restore the data affected by this update).
The short answer is: No.
However, you don't have to take the DB offline to do a partial restore on a table or tables.
You can restore a backup to a separate database and then use TSQL queries to restore the rows that were negatively impacted by your update. This can take place while the main database is online.
More info on restoring a database to a new location:
http://technet.microsoft.com/en-us/library/ms186390.aspx
For future reference, as per my comment,
It is a good practice to use a TRANSACTION.
-- Execute a transaction statement before doing an update.
BEGIN TRANSACTION
... < your update code >
Then if the update is wrong or produces undesired results, you can ROLLBACK the TRANSACTION
-- Ooops I screwed up! Let's rollback!
--ROLLBACK TRANSACTION -- I have this commented out and then just select the command when needed. This helps to not accidentally rollback if you just press CTRL+E, (or F5 in SSMS 2012)
... and it goes away :)
When all is well you just COMMIT the TRANSACTION.
-- COMMIT TRANSACTION -- commented out, see above
Or else you lock the database for all users!
So don't forget to commit!
Yes, besides doing a full restore, there is a viable solution provided by 3rd party tool, which reads information from a database transaction log, parse it, and then creates an undo T-SQL script in order to rollback user actions
Check out the How to recover SQL Server data from accidental updates without backups online article for more information. The article is focused on the UPDATE operation, but with appropriate settings and filters, you can rollback any other database change that's recorded within the transaction log
Disclaimer: I work as a Product Support Engineer at ApexSQL
It is not possible unless you version your data appropriately or do a restore.
Possible but It will require lot of efforts.
SQL Server maintains logs for DELETED/UPDATED/INSERTED data in non-readable format and to read them you should have the efficient tool Event Log Analyzer.
As a slightly modified version to the answers above, I sometimes like to use an automatically rolled back transaction in combination with the OUTPUT keyword and the INSERTED internal table to see what will actually update as a result set.
For instance,
BEGIN TRANSACTION;
UPDATE TableA
SET TableA.Column1 = #SomeValue
OUTPUT INSERTED.*
WHERE <condition>
ROLLBACK TRANSACTION;
If the result set looks good to me, then I'll change the last statement to COMMIT TRANSACTION;.

SQL Server 2005: Why Name Transactions?

I've been sorting out the whole nested transaction thing in SQL server, and I've gleamed these nuggets of understanding of behavior of nested trans':
When nesting transactions, only the
outermost commit will actually
commit.
"Commit Trans txn_name", when nested
, will always apply to the innermost
transaction, even if txn_name refers
to an outer transaction.
"ROLLBACK TRAN" (no name) , even in
an inner transaction, will rollback
all transactions.
"ROLLBACK TRAN txn_name" - txn_name must
refer to the outermost txn name.
If not, it will fail.
Given these , is there any benefit of naming transactions? You cannot use it to target a specific tranasction, either for commit or rollback.
Is it only for code commenting purposes?
Thanks,
Yoni
Effectively it's just a programmers aide memoire. If you're dealing with a Tx that has a number of inner transactions, giving each meaningful names can help you make sure that the tranactions are appropriately nested and may catch logic errors.
You can have procedures rollback only their own work on error, allowing the caller to decide wether to abandon the entire transaction or recover and try an alternate path. See Exception handling and nested transactions for a procedure template that allows this atomic behavior.
The idea is to roll back part of your work, like a nested transaction. Does not always work as intended.
Stored procedures using old-style error handling and savepoints may not work as intended when they are used together with TRY … CATCH blocks: Avoid mixing old and new styles of error handling.
Already discussed here ##ERROR and/or TRY - CATCH

Resources