繁体   English   中英

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

[英]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)
                {

                }
            }
        }
    }
}

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

“连接必须有效并且开放才能提交事务”

从根本上讲,问题是,您在finally块中提交了事务(该事务始终按设计运行),即使您可能已经回滚了事务并在catch块中关闭了连接。

比较简单的方法是在仍处于try块中的情况下提交事务,因为毕竟,您只想在try中的所有代码都成功的情况下提交事务。

话虽如此,您在try using一些奇怪的嵌套,并在其中using构造。 您应该尽量简化using s之类的内容。 这样,您也不必自己处理关闭的连接。 像这样:

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

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

我的错,是我自己使用“ finally”(最后)错误地搞定的。因此,如果第一次尝试查询失败,它将进入catch块,这将触发重新运行查询的调用。第二次查询执行将成功,事务将被提交。然后控制转到第一个查询的最后,它将再次尝试提交已经回滚的事务。 因此,它将引发该异常。 因此,如果将提交移至主要try块可解决此问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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