2

I'm running into an issue where changes made are being rolledback even when none of the queries throw an exception. It's strange since the code works in one environment but isn't committing changes in another.

Here is the function that handles the transaction. When I put a break point on the commit I hit the commit and I can see the changes in the database but when the transaction is disposed the changes are rolled back.

UPDATE:Additional tests show that it isn't a problem with the transaction. If the transaction is completely removed from the code below the app behaves in the same way. The changes are undone when the connection closes.

public bool Transaction(List<string> sqlStatements)
{
    using (SqlConnection conn = new SqlConnection(connectionString))
    {
        conn.Open();
        using (SqlTransaction tran = conn.BeginTransaction())
        {
            try
            {
                foreach (string query in sqlStatements)
                {
                    SqlCommand cmd = new SqlCommand(query, conn, tran);
                    cmd.CommandTimeout = 300;
                    cmd.ExecuteNonQuery();
                }

                tran.Commit();

                return true;
            }
            catch (SqlException sqlError)
            {
                tran.Rollback();
                //Log Exception
                return false;
            }
        }
    }
}
Robert
  • 75
  • 9
  • Why you know that there are no exception. You always catch the exception and do nothing with it ... just roll back the transaction – mybirthname Dec 30 '14 at 18:24
  • Code looks good for the transaction unit - though can be written in better ways. Are you sure you are not getting any exception as you had swallowed the exception in catch block. By executing above method, are you getting true or false return value? – StartingFromScratch Dec 30 '14 at 18:31
  • you should set a breakpoint inside of your catch block to see if it is ever hit and then check the exception before the catch returns false – mreyeros Dec 30 '14 at 18:35
  • A transaction, once committed, is never rolled back. That's technologically impossible. Delete the exception handling code. Don't rollback manually. Remove the bool-return based error reporting. – usr Dec 30 '14 at 18:37
  • @StartingFromScratch I'm sure I'm not getting exceptions. I'm able to trigger the same behavior while stepping through the code in debug mode. – Robert Dec 30 '14 at 22:24
  • @usr I've tried that and I get the same behavior. I also tried removing the transaction completely. When I did that the changes were rolled back when the connection closed. – Robert Dec 30 '14 at 22:26
  • @Robert are you using System.Transactions? Also, what does "@@TRANCOUNT" output? You expect it to be zero, right? – usr Dec 30 '14 at 23:18
  • @usr I'm using System.Data.SqlClient.SqlTransaction. I'm not using System.Transactions at this point. One odd thing I noticed, I get the same behavior if I remove the transaction completely. As if the database doesn't see the commit and does a rollback when the connection closes. – Robert Dec 30 '14 at 23:32
  • Perform the @@TRANCOUNT check that I asked for. It will help diagnose the issue. – usr Dec 31 '14 at 12:05
  • What @usr said about "once commited, is never rolled back" is not strictly true, if you have nested transactions it will only be committed when the outer most transaction is committed. The @@TRANCOUNT check will tell you if you are still inside a transaction, if you are getting 1 or more you are inside a nested transaction (I just wanted to clarify what usr was looking for). If the statements you are executing contains a `BEGIN TRAN` (or other transaction opening statement) with no corresponding `COMMIT` then that can cause problems (however closing trans out of should have errored). – Scott Chamberlain Dec 31 '14 at 14:25
  • @ScottChamberlain that's not a "transaction" in my book. The nesting level does not count as far as I'm concerned. Btw, because of nesting I asked for the @@TRANCOUNT check. – usr Dec 31 '14 at 15:12
  • @ScottChamberlain I've checked and none of the queries being run include a BEGIN TRAN. I'm looking at how best to get the @@TRANCOUNT into the session. – Robert Dec 31 '14 at 16:50

3 Answers3

0

Though I was sure, I tried your code at my end and it worked as expected. Again I am repeating that the method is good enough for the transaction handling. And once the transaction is committed, it can't be roll back.

In the above method, transaction disposal has got nothing to do with any rollback. I think, you have been debugging in wrong direction. Though, you may paste the original method here as you might be doing some other database operations.

Just out of blue, what kind of queries you have been firing? Do note that the DDL commands are auto-commit and transaction won't be effective.

StartingFromScratch
  • 628
  • 3
  • 10
  • 23
  • The queries are all insert/update/delete statements. I'm coming to the conclusion that there is an issue elsewhere, perhaps with a database setting. – Robert Dec 31 '14 at 15:56
  • If you have full recovery mode, you can still roll back to the moment in time immediately before the transaction was run. However, there may be other transactions involved in the rollback as well. – Joel Coehoorn Dec 31 '14 at 18:36
0

When you say you "can see the changes in the database", how are you determining this? I would expect them to be "in the database" if the following query returns the data that was "committed" (run this tsql after stepping over the commit call in Sql Server Management Studio for example):

-- Force the isolation level to "read committed" so we 
-- guarantee we are getting data that has definitely been committed.
-- If the data changes back, it must have been from a separate operation.
set transaction isolation level read committed
begin tran

select * from MyTableWithExpectedChanges;

-- You aren't changing anything so this can be rollback or commit
rollback tran

If the data did indeed commit, I would run a SQL Server Profiler session and see what is causing the data to revert back. It sounds like something separate is triggering to restore the data in that scenario.

If the data didn't commit, you have some sort of transaction count mismatch as per other comments.

Shiv
  • 1,274
  • 1
  • 19
  • 23
0

This issue was eventually tracked back to a trigger that had recently been updated to include a transaction.

We solved the issue by removing the transaction from the trigger.

Robert
  • 75
  • 9