views:

969

answers:

3

We have client app that is running some SQL on a SQL Server 2005 such as the following:

BEGIN TRAN;
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
COMMIT TRAN;

It is sent by one long string command.

If one of the inserts fail, or any part of the command fails, does SQL Server roll back the transaction? If it does not rollback, do I have to send a second command to roll it back?

I can give specifics about the api and language I'm using, but I would think SQL Server should respond the same for any language.

+2  A: 

If one of the inserts fail, or any part of the command fails, does SQL server roll back the transaction?

No, it does not.

If it does not rollback, do I have to send a second command to roll it back?

Sure, you should issue ROLLBACK instead of COMMIT.

If you want to decide whether to commit or rollback the transaction, you should remove the COMMIT sentence out of the statement, check the results of the inserts and then issue either COMMIT or ROLLBACK depending on the results of the check.

Quassnoi
So if I get an error, say "Primary key conflict" I need to send a second call to rollback? I guess that makes sense. What happens if there is a network-related error such as the connection is severed during a very long running SQL statement?
Jonathan.Peppers
When a connection times out, the underlying network protocol (e. g. `Named Pipes` or `TCP`) breaks the connection. When a connection is broken, `SQL Server` stops all currently running commands and rollbacks the transaction.
Quassnoi
So DyingCactus's solution looks like it fixes my issue, thanks for the help.
Jonathan.Peppers
If you need to abort on **any** error, then yes, this is the best option.
Quassnoi
+5  A: 

You are correct in that the entire transaction will be rolled back. You should issue the command to roll it back.

You can wrap this in a TRY CATCH block as follows

BEGIN TRY
    BEGIN TRANSACTION

        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);

    COMMIT TRAN -- Transaction Success!
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRAN --RollBack in case of Error

    -- you can Raise ERROR with RAISEERROR() Statement including the details of the exception
    RAISERROR(ERROR_MESSAGE(), ERROR_SEVERITY(), 1)
END CATCH
Raj More
I like DyingCactus's solution better, his is 1 line of code to change. If yours if for some reason better (or more reliable) let me know.
Jonathan.Peppers
The try catch gives you the ability to capture (and possibly fix) the error and raise a custom error message if required.
Raj More
Since we don't really care to handle the error specifically within SQL, I think we're going with DyingCactus's solution.
Jonathan.Peppers
+9  A: 

You can put "set xact_abort on" before your transaction to make sure sql rolls back automatically in case of error.

DyingCactus
Will this work on MS SQL 2K and higher? This seems the most simple solution.
Jonathan.Peppers
It appears in the docs for 2000, 2005, and 2008 so I assume yes. We are using it in 2008.
DyingCactus
Is there an option to rollback on a network timeout or network errors in general? Or does this option handle all in one?
Jonathan.Peppers
This will handle run-time sql errors only. Quassnoi has already answered the network connection question.
DyingCactus