So fangen Sie SQLServer-Timeout-Ausnahmen ab

117

Ich muss speziell SQL Server-Timeout-Ausnahmen abfangen, damit sie unterschiedlich behandelt werden können. Ich weiß, dass ich die SqlException abfangen und dann überprüfen kann, ob die Nachrichtenzeichenfolge "Timeout" enthält, habe mich aber gefragt, ob es einen besseren Weg gibt, dies zu tun.

try
{
    //some code
}
catch (SqlException ex)
{

    if (ex.Message.Contains("Timeout"))
    {
         //handle timeout
    }
    else
    {
         throw;
    }
}
brodie
quelle
Suchen Sie nach einem ConnectionTimeout oder einem CommandTimeout, dh erwarten Sie, dass die Verbindung fehlschlägt oder der ausgeführte Befehl fehlschlägt?
Edosoft
Ich suche nach einem CommandTimeout, das auf einen Standard von 30 Sekunden eingestellt ist, glaube ich
brodie

Antworten:

157

Ich glaube, Sie überprüfen den Wert von ex.Number, um nach einer Zeitüberschreitung zu suchen. Wenn es -2 ist, haben Sie eine Zeitüberschreitungssituation.

-2 ist der Fehlercode für das Zeitlimit, der von DBNETLIB, dem MDAC-Treiber für SQL Server, zurückgegeben wird. Dies können Sie sehen, indem Sie Reflector herunterladen und unter System.Data.SqlClient.TdsEnums nach TIMEOUT_EXPIRED suchen.

Ihr Code würde lauten:

if (ex.Number == -2)
{
     //handle timeout
}

Code zum Nachweis eines Fehlers:

try
{
    SqlConnection sql = new SqlConnection(@"Network Library=DBMSSOCN;Data Source=YourServer,1433;Initial Catalog=YourDB;Integrated Security=SSPI;");
    sql.Open();

    SqlCommand cmd = sql.CreateCommand();
    cmd.CommandText = "DECLARE @i int WHILE EXISTS (SELECT 1 from sysobjects) BEGIN SELECT @i = 1 END";
    cmd.ExecuteNonQuery(); // This line will timeout.

    cmd.Dispose();
    sql.Close();
}
catch (SqlException ex)
{
    if (ex.Number == -2) {
        Console.WriteLine ("Timeout occurred");
    }
}
Jonathan
quelle
Ja, das ist ziemlich genau das, was ich im Moment mache, aber es ist nicht sehr elegant, nach -2 zu
suchen
12
Laden Sie den Reflektor von Red Gate herunter und suchen Sie nach TIMEOUT_EXPIRED. Es befindet sich in System.Data.SqlClient.TdsEnums und hat einen Wert von -2. : o)
Jonathan
2
Für diejenigen, die keinen Zugang zu Reflector haben: link
ankitk
4
@brodie Deshalb solltest du eine Konstante dafür machen und kannst in einem Kommentar zur Konstante erklären, woher der "magische" Wert stammt.
Jason L.
18

hier: http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.adonet/2006-10/msg00064.html

Sie können auch lesen, dass Thomas Weingartner schrieb:

Zeitüberschreitung: SqlException.Number == -2 (Dies ist ein ADO.NET-Fehlercode)
Allgemeiner Netzwerkfehler: SqlException.Number == 11
Deadlock: SqlException.Number == 1205 (Dies ist ein SQL Server-Fehlercode)

...

Wir behandeln den "Allgemeinen Netzwerkfehler" auch als Timeout-Ausnahme. Dies tritt nur in seltenen Fällen auf, z. B. wenn Ihre Abfrage zum Aktualisieren / Einfügen / Löschen einen lang laufenden Auslöser auslöst.

Roland Pihlakas
quelle
6

Aktualisiert für c # 6:

    try
    {
        // some code
    }
    catch (SqlException ex) when (ex.Number == -2)  // -2 is a sql timeout
    {
        // handle timeout
    }

Sehr einfach und schön anzusehen !!

John Evans
quelle
0

Was ist der Wert für die SqlException.ErrorCode-Eigenschaft? Kannst du damit arbeiten?

Bei Zeitüberschreitungen kann es sich lohnen, den Code auf -2146232060 zu überprüfen .

Ich würde dies als statische Konstante in Ihrem Datencode einrichten.

Rob Cooper
quelle
2
Wenn ich mir die Dokumente für ErrorCode anschaue, scheint es mir, dass es Interop-Level-Fehler meldet. Es kann also eher auf der Ebene der COM-Fehler liegen oder dass ein Anbieter (im Allgemeinen) auf eine Ausnahme gestoßen ist, anstatt auf einen bestimmten Fehler in Bezug auf Ihre Aktivitäten.
Eric Tuttleman
@Eric ist korrekt - das ist ein HRESULT-Code für den SqlException-Typ, nicht für die Quelle der Ausnahme.
Codekaizen
0

Ich bin nicht sicher, aber wenn wir eine Zeitüberschreitung bei der Ausführung oder eine Befehlszeitüberschreitung haben Der Client sendet ein "ABORT" an SQL Server und gibt dann einfach die Abfrageverarbeitung auf. Es wird keine Transaktion zurückgesetzt, es werden keine Sperren freigegeben. Um dieses Problem zu lösen, entferne ich die Transaktion in der gespeicherten Prozedur und verwende die SQL-Transaktion in meinem .NET-Code, um die sqlException zu verwalten

hamid reza Heydari
quelle