2013-03-08 23 views
10

Ho ricevuto l'errore successivo una volta nella mia applicazione.SQLTransaction ha completato l'errore

Questo SQLTransaction è stato completato; essa non è più utilizzabile

Stack Trace è fissato al di sotto - Si dice di Zombie Check e Rollback.

Qual è l'errore nel codice?

Nota: questo errore è venuto solo una volta.

UPDATE

Da MSDN - SqlTransaction.Rollback Method

un rollback genera un'InvalidOperationException se la connessione viene terminata o se la transazione è già stato rotolato indietro sul server.

Da Zombie check on Transaction - Error

Uno dei motivi più frequenti che ho visto questo errore mostrando in varie applicazioni è, condivisione SqlConnection attraverso la nostra applicazione.

CODICE

public int SaveUserLogOnInfo(int empID) 
{ 
     int? sessionID = null; 
     using (SqlConnection connection = new SqlConnection(connectionString)) 
     { 
      connection.Open(); 
      SqlTransaction transaction = null; 
      try 
      { 
       transaction = connection.BeginTransaction(); 
       sessionID = GetSessionIDForAssociate(connection, empID, transaction); 

        //Other Code 

       //Commit 
       transaction.Commit(); 
      } 
      catch 
      { 
       //Rollback 
       if (transaction != null) 
       { 
        transaction.Rollback(); 
        transaction.Dispose(); 
        transaction = null; 
       } 

       //Throw exception 
       throw; 
      } 
      finally 
      { 
       if (transaction != null) 
       { 
        transaction.Dispose(); 
       } 
      } 
     } 

     return Convert.ToInt32(sessionID,CultureInfo.InvariantCulture); 

    } 

Stack Trace

enter image description here


RIFERIMENTO:

  1. What is zombie transaction?
  2. Zombie check on Transaction - Error
  3. SqlTransaction has completed
  4. http://forums.asp.net/t/1579684.aspx/1
  5. "This SqlTransaction has completed; it is no longer usable."... configuration error?
  6. dotnet.sys-con.com - SqlClient Connection Pooling Exposed
  7. Thread abort leaves zombie transactions and broken SqlConnection

+1

Qual è l'eccezione che causa il codice per raggiungere il 'catch'? – Maarten

+1

In questo caso è necessario utilizzare un'istruzione "using" per la transazione. Vedi http://stackoverflow.com/questions/1127830/why-use-a-using-statement-with-a-sqltransaction – Maarten

+1

@Maarten per essere onesti, l'OP * fa * assicurarsi che venga smaltito; ma sono d'accordo che * non * usando 'using' lo rende troppo complesso –

risposta

5

Si dovrebbe lasciare un po 'del lavoro al compilatore, per avvolgerlo in un try/catch/finally per voi.

Inoltre, è possibile prevedere che lo Rollback possa occasionalmente generare un'eccezione, se si verifica un problema nella fase Commit o se una connessione al server si interrompe. Per questo motivo è necessario includerlo in un valore try/catch.

try 
{ 
    transaction.Rollback(); 
} 
catch (Exception ex2) 
{ 
    // This catch block will handle any errors that may have occurred 
    // on the server that would cause the rollback to fail, such as 
    // a closed connection. 
    Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType()); 
    Console.WriteLine(" Message: {0}", ex2.Message); 
} 

Questo viene copiato esattamente da MSDN documentation page for Rollback method.

Vedo che sei preoccupato di avere una transazione di zombi. Nel caso in cui hai incollato, non sembra che tu abbia un problema. La transazione è stata completata e non dovresti più averne a che fare. Rimuovi i riferimenti ad essa se li tieni, e dimenticatene.


Da MSDN - SqlTransaction.Rollback Method

un rollback genera un'InvalidOperationException se la connessione viene terminata o se la transazione è già stato rotolato indietro sul server.

rigenerare una nuova eccezione per dire all'utente che i dati non potrebbero essere stati salvati, e chiederle di aggiornare e rivedere

+0

C'è un avviso critico in arrivo nell'analisi del codice, se ingoio un'eccezione. Ciò significa che se non lancio l'eccezione 'catch'. – Lijo

+0

Quindi si è verificato un problema con i criteri di analisi. Non riesco a credere che tu non permetta l'effettiva gestione delle eccezioni? Butta tutte le eccezioni all'utente? –

+0

Sì, ho bisogno di registrare l'eccezione e lanciarla sul front-end. Lancio la mia eccezione personalizzata, solitamente, nell'applicazione client. – Lijo

6

Nota: questo errore è venuto solo una volta.

quindi è molto difficile dire molto; potrebbe essere semplicemente che il // Other Code ecc ha impiegato molto tempo e l'intera cosa è stata uccisa. Forse la tua connessione è morta, o un amministratore l'ha deliberatamente ucciso perché stavi bloccando.

Qual è l'errore nel codice?

troppo complicato; può essere molto più semplice:

using (var connection = new SqlConnection(connectionString)) 
{ 
    connection.Open(); 
    using(var transaction = connection.BeginTransaction()) 
    { 
     try 
     { 
      sessionID = GetSessionIDForAssociate(connection, empID, transaction); 
      //Other Code 
      transaction.Commit(); 
     } 
     catch 
     { 
      transaction.Rollback(); 
      throw; 
     } 
    } 
} 

molto meno codice per sbagliare.

+3

nel tuo caso potresti salvare più righe, se rimuovi il try catch .. con l'istruzione" using "una transazione viene automaticamente ripristinata se un'eccezione succede ... vedi http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqltransaction.aspx – nWorx

+0

Grazie. Ma non capisco perché il codice suggerito risolverà il problema. È perché non stai chiamando 'Dispose()'? – Lijo

+0

@nWorx ancora meglio –

0

Questo messaggio è semplicemente perché che ha scritto il codice che genera un'eccezione dopo la transazione ha stato già eseguito correttamente con successo. Prova a verificare il codice che hai scritto dopo il metodo Commit o puoi gestirlo utilizzando Try..Catch e infine Blocks :).

1

Ho riscontrato questo errore una volta e sono rimasto bloccato e incapace di sapere cosa sta andando storto. In realtà stavo cancellando un record e nella procedura Stored non stavo cancellando suo figlio e specialmente l'istruzione delete in Stored Procedure era all'interno del limite Transaction. Ho rimosso che il codice di transazione da stored procedure e sono liberato di questo errore di “This SqlTransaction has completed; it is no longer usable.”

1

io uso codice qui sotto in grado di riprodurre questo errore, io uso 1000 compiti da eseguire Sql, dopo circa 300 attività completate con successo, un sacco di eccezioni su timeout error iniziare a verificarsi sul ExecuteNonQuery(),

poi la prossima errore This SqlTransaction has completed avverrà sulla transaction.RollBack(); e il suo stack di chiamate contiene anche ZombieCheck().

(Se un singolo programma con 1000 attività di pressione non è sufficiente, è possibile eseguire più file exe compilati allo stesso tempo, o addirittura utilizzare più computer esegui su un DataBase.

Quindi penso che uno dei motivi per cui questo errore può essere qualcosa di sbagliato in Connection, quindi causare l'errore transazione si verifica pure.

Task[] tasks = new Task[1000]; 
for (int i = 0; i < 1000; i++) 
{ 
    int j = i; 
    tasks[i] = new Task(() => 
     ExecuteSqlTransaction("YourConnectionString", j) 
     ); 
} 

foreach (Task task in tasks) 
{ 
    task.Start(); 
}  

/////////////  

public void ExecuteSqlTransaction(string connectionString, int exeSqlCou) 
{ 

    using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 
     connection.Open(); 

     SqlCommand command = connection.CreateCommand(); 
     SqlTransaction transaction; 

     // Start a local transaction. 
     transaction = connection.BeginTransaction(); 

     // Must assign both transaction object and connection 
     // to Command object for a pending local transaction 
     command.Connection = connection; 
     command.Transaction = transaction; 

     try 
     { 
      command.CommandText = 
       "select * from Employee"; 
      command.ExecuteNonQuery(); 

      // Attempt to commit the transaction. 
      transaction.Commit(); 

      Console.WriteLine("Execute Sql to database." 
       + exeSqlCou); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Commit Exception Type: {0}", ex.GetType()); 
      Console.WriteLine(" Message: {0}", ex.Message); 


      // Attempt to roll back the transaction. 
      try 
      { 
       transaction.Rollback(); 
      } 
      catch (Exception ex2) 
      { 
       // This catch block will handle any errors that may have occurred 
       // on the server that would cause the rollback to fail, such as 
       // a closed connection. 
       Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType()); 
       Console.WriteLine(" Message: {0}", ex2.Message); 

      } 
     } 
    } 
} 

Inoltre trovo se commetto due volte sequentailly richiamerà questa eccezione pure.

 transaction.Commit(); 
     transaction.Commit(); 

Oppure se Connection Closed before commit attiva anche questo errore.

 connection.Close(); 
     transaction.Commit(); 

Aggiornamento:

Trovo strano che creo un'altra nuova tabella e inserire 500 mila i dati ad esso,

quindi utilizzare 100000 attività con select * from newtable sql, in esecuzione 5 programmi al Allo stesso tempo, questa volta si verifica l'errore di timeout, ma quando transaction.Rollback() non ha richiamato il SQLTransaction has completed error.

ma se si verifica l'errore di timeout, passare al blocco catch e nel blocco catch fare nuovamente transaction.Commit(), SQLTransaction has completed error.

Problemi correlati