简体   繁体   中英

Connection must be valid and open to commit transaction for sqllite database while retrying to execute the failed query

public static void SetStatus( Status statusObject,int retryCount)
{
    if (statusObject != null)
    {
        using (SqliteConnection dbConn = new SqliteConnection(dbURL))
        {
            IDbTransaction dbTransaction = null;
            try
            {
                dbConn.Open();
                dbTransaction = dbConn.BeginTransaction();
                new SqliteCommand(some_query, dbConn).ExecuteNonQuery();
            }
            catch (Exception e)
            {
                dbTransaction.Rollback();
                dbConn.Close();
                if (retryCount > 0)
                {
                    SetStatus(statusObject, --retryCount);
                    return;
                }
                else
                    throw e;
            }
            finally
            {
                try { dbTransaction.Commit(); }
                catch (Exception e)
                {

                }
            }
        }
    }
}

Whenever ExecuteNonQuery fails due due to some exception I have a retry mechanism which will run the same query again.In that case during the second time(while retrying) the following exception comes-

"Connection must be valid and open to commit transaction"

The problem is basically, that you commit the transaction in the finally block—which runs always per design—even though you may already have rolled back the transaction and closed the connection in the catch block.

The easier way would be to commit the transaction while still in the try block, because after all, you only want to commit the transaction if all the code in the try succeeded.

That being said, you are having some odd nesting with the try and using constructs there. You should try to keep things like using s as concise as possible. That way you will also not have to deal with closing connections yourself. Something like this:

public static void SetStatus(Status statusObject, int retryCount)
{
    if (statusObject == null)
        return;

    try
    {
        using (var dbConn = new SqliteConnection(dbURL))
        {
            IDbTransaction dbTransaction = null;
            try
            {
                dbConn.Open();
                dbTransaction = dbConn.BeginTransaction();
                new SqliteCommand(some_query, dbConn).ExecuteNonQuery();
                dbTransaction.Commit();
            }
            catch
            {
                // transaction might be null if the connection couldn’t be opened
                dbTransaction?.Rollback();
                throw;
            }
        }
    }
    catch (Exception ex)
    {
        if (retryCount > 0)
            SetStatus(statusObject, --retryCount);
        else
            throw ex;
    }
}

One final note, one could argue that using a transaction is absolutely not necessary here: You are only executing a single query on this database connection, so either that works, or it will fail in which case there is not something to rollback anyway. So unless you are having multiple queries there, you don't need an explicit transaction (but I'll just assume that you just reduced your example to show just a single query).

My bad,screwed up using "finally" improperly myself.So if the query fails at first attempt it would go to catch block which will fire the call to re run the query.Second time query execution would be successful and transaction would be committed.Then the control goes to finally of first query which will again try to commit the already rolled back transaction. So,it would throw that exception. So,if the moving the commit to main try block fixed the issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM