连接必须有效并且在重试执行失败的查询时打开以提交sqllite数据库的事务

时间:2017-08-01 06:58:34

标签: c# .net sqlite

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)
                {

                }
            }
        }
    }
}

每当ExecuteNonQuery由于某些异常而失败时,我都会有一个重试机制,它将再次运行相同的查询。在这种情况下,第二次(重试时)会出现以下异常 -

"连接必须有效并且打开以提交事务"

2 个答案:

答案 0 :(得分:2)

问题基本上是,您在finally块中提交事务 - 它始终按设计运行 - 即使您可能已经回滚了事务并关闭了catch块中的连接

更简单的方法是在try块中提交事务,因为毕竟,如果try中的所有代码都成功,您只想提交事务。

话虽如此,你正在使用tryusing构造进行奇怪的嵌套。您应尽量使using之类的内容尽可能简洁。这样你也不必自己处理关闭连接。像这样:

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;
    }
}

最后一点,人们可能会争辩说,在这里使用事务绝对没有必要:你只是在这个数据库连接上执行一个查询,所以要么工作,要么失败,在这种情况下没有回滚的东西无论如何。因此,除非您在那里有多个查询,否则您不需要显式事务(但我只是假设您只是简化了示例以显示单个查询)。

答案 1 :(得分:0)

我的坏,搞砸了“最后”不正确地使用自己。所以如果查询在第一次尝试时失败,它将进入catch块,这将触发调用以重新运行查询。第二次查询执行将成功并且事务将然后,控件转到第一个查询的最后一个查询,它将再次尝试提交已经回滚的事务。所以,它会引发异常。 因此,如果将提交移动到主try块,则修复了问题。