it-swarm.com.de

"Diese SqlTransaction wurde abgeschlossen; sie ist nicht mehr verwendbar."

Ich arbeite seit ungefähr anderthalb Tagen daran und habe zahlreiche Blogs und Hilfeartikel im Web durchsucht. Ich habe einige Fragen zu SO gefunden, die sich auf diesen Fehler beziehen, aber ich dachte nicht, dass sie sich ganz auf meine Situation beziehen würden (oder in einigen Fällen konnte ich sie leider nicht gut genug verstehen, um sie zu implementieren: P). Ich bin mir nicht sicher, ob ich das gut genug beschreiben kann ... aber hier geht es:

Wir haben eine .NET-App, um unsere Ressourcen zu verfolgen. Es gibt eine Exportfunktion, um eine Ressource in das Zeiterfassungssystem und das Abrechnungssystem zu kopieren. Dadurch wird auf eine gespeicherte Prozedur zugegriffen, die eine Verbindung zu den Zeit- und Rechnungsdatenbanken herstellt.

Ich habe kürzlich die Datenbank des Abrechnungssystems auf einen neuen Server verschoben (ursprünglicher Server: Server 2003 SP2, SQL 2005; neuer Server: Server 2008 R2, SQL 2008 R2). Ich habe einen Linked Server eingerichtet, der auf die 2008-Datenbanken verweist. Ich habe die gespeicherte Prozedur so aktualisiert, dass sie auf den Server 2008 verweist, und dann wurde eine Fehlermeldung über MSDTC und RPC angezeigt (http://www.safnet.com/writing/tech/archives/2007/06/server_myserver.html). Ich habe 'rpc/rpc out' auf dem Linked Server aktiviert und MSDTC so eingestellt, dass Netzwerkzugriff möglich ist (etwa: http://www.sqlwebpedia.com/content/msdtc-truffer ).

Jetzt bekomme ich das obige, wenn ich versuche, die Exportfunktion auszuführen: "Diese SqlTransaction ist abgeschlossen, sie ist nicht mehr verwendbar." Was mir merkwürdig erscheint, ist, wenn ich die gespeicherte Prozedur (von SSMS) gerade ausführe, heißt es, dass sie erfolgreich abgeschlossen wurde. 

Hat jemand das schon mal gesehen? Hab ich bei der Konfiguration etwas verpasst? Ich werde immer wieder die gleichen Seiten durchgehen und das einzige, was ich fand, war, dass ich nach den MSDTC-Änderungen (siehe hier: http://social.msdn.Microsoft.com/forums/en-US) keinen Neustart durchgeführt habe/adodotnetdataproviders/thread/7172223f-acbe-4472-8cdf-feec80fd2e64/ ).

Ich kann einen Teil oder die gesamte gespeicherte Prozedur posten, wenn es helfen würde ... lass es mich wissen.

41
White Island

Ich glaube, dass diese Fehlermeldung auf eine "Zombie-Transaktion" zurückzuführen ist.

Suchen Sie nach möglichen Bereichen, in denen das Transacton zweimal festgeschrieben wird (oder zweimal zurückgesetzt oder zurückgesetzt und festgeschrieben wird usw.). Übernimmt der .NET-Code die Transaktion, nachdem SP sie bereits festgeschrieben hat? Rollt der .Net-Code bei einem Fehler zurück und versucht, ihn in einer catch-Klausel (oder zum Schluss) erneut zurückzusetzen?

Es ist möglich, dass auf dem alten Server nie eine Fehlerbedingung aufgetreten ist, und daher wurde der fehlerhafte "Double Rollback" -Code nie getroffen. Möglicherweise haben Sie jetzt eine Situation, in der es gibt einen Konfigurationsfehler auf dem neuen Server, und jetzt wird der fehlerhafte Code über die Ausnahmebehandlung getroffen.

Kannst du den Fehlercode debuggen? Hast du eine Stack-Spur?

40
Phil Sandler

Ich hatte dies kürzlich nach einem Refactoring in einem neuen Verbindungsmanager. Eine neue Routine akzeptierte eine Transaktion, sodass sie als Teil eines Batches ausgeführt werden konnte. Das Problem bestand in einem Verwendungsblock:

public IEnumerable<T> Query<T>(IDbTransaction transaction, string command, dynamic param = null)
{
  using (transaction.Connection)
  {
    using (transaction)
    {
      return transaction.Connection.Query<T>(command, new DynamicParameters(param), transaction, commandType: CommandType.StoredProcedure);
    }
  }
}

Es sieht so aus, als ob der äußere Benutzer die zugrunde liegende Verbindung geschlossen hat. Daher wurde bei allen Versuchen, die Transaktion festzuschreiben oder einen Rollback auszuführen, die Nachricht "This SqlTransaction has completed; it is no longer usable." ausgegeben.

Ich entfernte die Usings, fügte einen Bedeckungstest hinzu und das Problem wurde behoben.

public IEnumerable<T> Query<T>(IDbTransaction transaction, string command, dynamic param = null)
{
  return transaction.Connection.Query<T>(command, new DynamicParameters(param), transaction, commandType: CommandType.StoredProcedure);
}

Überprüfen Sie, ob die Verbindung innerhalb einer Transaktion geschlossen werden kann.

6
Phil Cooper

Ich bin kürzlich auf eine ähnliche Situation gestoßen. Öffnen Sie zum Debuggen in einer VS IDE -Version Ausnahmen von Debug (Strg + D, E). Aktivieren Sie alle Kontrollkästchen gegen die Spalte "Thrown" und führen Sie die Anwendung im Debug-Modus aus. Ich habe festgestellt, dass eine der Tabellen nicht ordnungsgemäß in die neue Datenbank importiert wurde. Daher brach die interne SQL-Ausnahme die Verbindung ab und führte zu diesem Fehler. 

Der Kern der Geschichte ist: Wenn der Code, der zuvor ausgeführt wurde, diesen Fehler in einer neuen Datenbank zurückgibt, könnte dies ein Problem mit dem fehlenden Datenbankschema sein. 

Hoffe, es hilft.... HydTechie

3
HydPhani

In meinem Fall bestand das Problem darin, dass eine der in der Transaktion enthaltenen Abfragen eine Ausnahme auslöste, und obwohl die Ausnahme "ordnungsgemäß" behandelt wurde, konnte die gesamte Transaktion trotzdem zurückgesetzt werden.

Mein Pseudo-Code war wie folgt:

var transaction = connection.BeginTransaction();
for(all the lines in a file)
{
     try{
         InsertLineInTable(); // INSERT statement might fail and throw an exception
     }
     catch {
         // notify the user about the error on line x and continue
     }
}

// Commit and Rollback will fail if one of the queries 
// in InsertLineInTable threw an exception
if(CheckTableForErrors())
{
    transaction.Commit();
}
else
{
    transaction.Rollback();
}
3
Loris

Ich habe das gleiche Problem. Dieser Fehler tritt auf, weil das Verbindungs-Pooling erfolgt Wenn zwei oder mehr Benutzer auf das System zugreifen, verwenden das Verbindungspooling eine Verbindung und die Transaktion ebenfalls. Wenn der erste Benutzer ein Commit oder ein Rollback ausführt, ist die Transaktion nicht langlebig.

2
Ademilso Peres

Überprüfen Sie auch, ob in Ihrer .NET-App lange laufende Prozesse in der Datenbank ausgeführt werden. Beispielsweise rufen Sie möglicherweise eine gespeicherte Prozedur oder eine Abfrage auf, die nicht genug Zeit hat, um abzuschließen, was in Ihren Protokollen wie folgt angezeigt werden kann:

  • Ausführungszeitlimit abgelaufen. Das Zeitlimit, das vor dem Abschluss der Operation verstrichen ist oder der Server antwortet nicht.

    • Diese SqlTransaction wurde abgeschlossen. es ist nicht mehr verwendbar.

Überprüfen Sie die Befehlszeitlimiteinstellungen Versuchen Sie, eine Ablaufverfolgung (Profiler) auszuführen, und sehen Sie, was auf der DB-Seite passiert ...

1
Milan

Hier ist eine Möglichkeit, die Zombie-Transaktion zu erkennen

SqlTransaction trans = connection.BeginTransaction();

//some db calls here

if (trans.Connection != null) //Detecting zombie transaction
{
  trans.Commit();
}

Beim Dekompilieren der SqlTransaction-Klasse wird Folgendes angezeigt

public SqlConnection Connection
{
  get
  {
    if (this.IsZombied)
      return (SqlConnection) null;
    return this._connection;
  }
}

Ich merke, wenn die Verbindung geschlossen wird, wird das transOP zum Zombie und kann daher nicht Commit sein. In meinem Fall liegt es daran, dass ich die Commit() in einem finally-Block habe, während die Verbindung im try-Block war. Diese Anordnung bewirkt, dass die Verbindung entsorgt und Müll gesammelt wird. Die Lösung bestand darin, stattdessen Commit im try-Block zu platzieren.

0
Jeson Martajaya

In meinem Fall habe ich einige Codes nach dem Festschreiben der Transaktion beim gleichen try catch-Block. Ein Fehler kann dazu führen, dass die Ausführung einen Block abfängt, der das Transaktions-Rollback enthält. Es wird der ähnliche Fehler angezeigt. Schauen Sie sich zum Beispiel die folgende Codestruktur an:

SqlTransaction trans = null;

try{
 trans = Con.BeginTransaction();
// your codes

  trans.Commit();
//your codes having errors

}
catch(Exception ex)
{
     trans.Rollback(); //transaction roll back
    // error message
}

finally
{ 
    // connection close
}

Hoffe es wird jemandem helfen :)

0
Amal P S