2017-08-01 4 views
0
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) 
       { 

       } 
      } 
     } 
    } 
} 

「最終的には」不適切myself.Soクエリが最初に失敗した場合に使用してめちゃくちゃに二回(再試行中)接続はsqlliteデータベースのトランザクションのコミットを有効かつオープンでなければならないのExecuteNonQueryが原因私は中にそのような場合again.In同じクエリを実行する再試行メカニズムを持っているいくつかの例外が原因で失敗したときはいつでも

「接続がトランザクションをコミットするために有効で、開いていなければなりません」comes-次の例外

+0

最後に、コミット後にdb接続を閉じます。 –

答えて

0

問題は基本的には、すでにトランザクションをロールバックして、catchブロック内の接続を閉じていても、デザインごとに常に実行されるfinallyブロックでトランザクションをコミットすることです。

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

それはまさに私がやったことです。説明に感謝します。 – DChamp

0

私の悪いです、それはクエリを再実行する呼び出しを発生させるブロックをキャッチするようにしようとします。2番目の時間のクエリの実行は成功し、トランザクションはコミットされます。その後、制御は、すでにロールバックされたトランザクションを再度コミットしようとする最初のクエリに行きます。したがって、その例外がスローされます。 したがって、メインのtryブロックへのコミットが問題を修正した場合。

関連する問題