Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Microsoft. Data.SqlClient rapporterar server- och leverantörsfel genom SqlException. En databasoperation kan returnera flera fel, så inspektera undantagets Errors samling istället för att bara förlita dig på den kombinerade Message.
Varningar och informationsmeddelanden från databasmotorn levereras via InfoMessage. Prenumerera innan du öppnar anslutningen eller utför kommandot som kan generera meddelandet.
Hantera ett databasfel i denna ordning:
- Fånga
SqlExceptionvid en gräns som kan lägga till operationskontext eller välj en återställningsåtgärd. - Inspektera alla
SqlErroriErrors-samlingen. - Registrera strukturerade diagnosfält utan att registrera inloggningsuppgifter eller känsliga värden.
- Kontrollera anslutningstillståndet efter ett anslutningsrelaterat fel.
- Försök igen endast när felet är övergående och operationen är säker att upprepa.
Exemplen i denna artikel förutsätter att en öppen SqlConnection med namnet connection riktar sig mot AdventureWorks exempeldatabas. C#-exemplen kräver using Microsoft.Data.SqlClient;.
Ta emot informationsmeddelanden
Händelsen InfoMessage tar emot servermeddelanden med låg svårighetsgrad, inklusive utdata från PRINT. En händelse kan innehålla flera SqlError objekt. Abonnera innan du utför kommandot som kan producera ett meddelande:
connection.InfoMessage += (_, eventArgs) =>
{
foreach (SqlError message in eventArgs.Errors)
{
Console.WriteLine(
$"Info {message.Number}, class {message.Class}: {message.Message}");
}
};
using var command = new SqlCommand(
"PRINT N'Connected and ready.';",
connection);
command.ExecuteNonQuery();
Utdraget visas:
Info 0, class 0: Connected and ready.
Fånga SqlException
Fånga SqlException runt databasoperationen som du kan hantera eller berika. Använd inte en allmän catch-sats för att förvandla en misslyckad databasoperation till ett lyckat resultat.
En databasoperation kan returnera mer än ett fel. Varje del i Errors innehåller strukturerade fält:
| Property | Meaning |
|---|---|
Number |
Felnummer för databasmotor eller leverantör. |
Class |
Allvarlighetsgrad. |
State |
Serverdefinierat tillstånd som kan särskilja positioner för samma felnummer. |
LineNumber |
Rapporterat linjenummer. |
Procedure |
Procedur- eller triggernamn när det tillhandahålls. |
Server |
Servernamn som rapporterats för felet. |
Message |
Läsbar feltext. |
Bekvämlighetsegenskaperna på SqlException, inklusive Number, Class, , State, LineNumber, Procedure, och Server, återspeglar endast det första felet. Följande utdrag skriver ut ett meddelande och utlöser sedan ett fel i samma batch. Den läser exception.Number och itererar Errors sedan för att rapportera varje post:
using (var failing = new SqlCommand("""
PRINT N'Starting controlled operation.';
RAISERROR (N'The controlled operation failed.', 16, 1);
""", connection))
{
try
{
await failing.ExecuteNonQueryAsync();
}
catch (SqlException exception)
{
Console.WriteLine($"First error number: {exception.Number}");
foreach (SqlError error in exception.Errors)
{
Console.WriteLine(
$"Number={error.Number}; Class={error.Class}; " +
$"State={error.State}; Message={error.Message}");
}
}
}
Utdraget skrivs ut:
First error number: 50000
Number=50000; Class=16; State=1; Message=The controlled operation failed.
Number=0; Class=0; State=1; Message=Starting controlled operation.
Utgången PRINT höjer inte InfoMessage. När en batch returnerar ett fel som utlöser SqlException, lägger leverantören till batchens informationsmeddelanden i slutet av SqlException.Errors.
Detta utdrag fångar det kontrollerade felet endast för att visa dess fält. I applikationskod, vidarebefordra undantaget med throw; om inte catch-blocket väljer en verklig återställningsåtgärd. Fatta beslut utifrån dokumenterade felnummer och driftkontext. Tolka inte lokaliserad meddelandetext.
Kontrollera anslutningstillståndet
Databasmotorn tilldelar varje meddelande en allvarlighetsklass. Lägre klasser är informativa. Klasser som behandlas som fel ger SqlException. Fel med hög allvarlighetsgrad kan göra anslutningen stängd eller trasig.
Efter ett fel, kontrollera State innan du återanvänder anslutningen:
using var command = new SqlCommand(
"RAISERROR (N'Controlled failure.', 16, 1);",
connection);
try
{
command.ExecuteNonQuery();
}
catch (SqlException)
{
Console.WriteLine($"Connection state: {connection.State}");
}
Anta inte att en anslutning förblir användbar bara för att undantaget fångades. Ett fel på allvarlighetsgrad 16 lämnar den vanligtvis öppen, men anslutningsavbrott kan stänga den. Kassera en stängd eller trasig anslutning och skaffa en ny anslutning från anslutningspoolen. Koda inte återförsökspolicyn enbart utifrån allvaret. Operationen måste också kunna upprepas säkert.
Identifiera ett misslyckat batchkommando
När en SqlBatch misslyckas SqlException.BatchCommand kan referera till den associerade SqlBatchCommand. Egenskapen är null när providern inte kan härleda felet till ett batchkommando. Följande utdrag kör två batchkommandon. Den andra misslyckas:
using (var batch = new SqlBatch(connection))
{
batch.BatchCommands.Add(new SqlBatchCommand("SELECT 1;"));
batch.BatchCommands.Add(new SqlBatchCommand("SELECT 1 / 0;"));
try
{
await batch.ExecuteNonQueryAsync();
}
catch (SqlException exception)
{
Console.WriteLine($"Error {exception.Number}: {exception.Message}");
if (exception.BatchCommand is SqlBatchCommand failedCommand)
{
Console.WriteLine($"Failed command: {failedCommand.CommandText}");
}
}
}
Utdraget skrivs ut:
Error 8134: Divide by zero error encountered.
Failed command: SELECT 1 / 0;
Kommandotext kan innehålla känsliga literaler i dåligt parametriserade applikationer. Föredra stabila operationsnamn för applikationen i produktionsloggar och logga inte parametervärden som standard.
Skicka användarfel till InfoMessage
FireInfoMessageEventOnUserErrors har som standard false. När du sätter den till true, går fel med svårighetsgrad 16 eller lägre till InfoMessage-hanteraren istället för att utlösa SqlException:
connection.InfoMessage += (_, eventArgs) =>
{
foreach (SqlError message in eventArgs.Errors)
{
Console.WriteLine(
$"Info {message.Number}, class {message.Class}: {message.Message}");
}
};
connection.FireInfoMessageEventOnUserErrors = true;
using var command = new SqlCommand(
"RAISERROR (N'Routed to InfoMessage.', 16, 1);",
connection);
command.ExecuteNonQuery();
Inget undantag kastas. Utdraget skrivs ut:
Info 50000, class 16: Routed to InfoMessage.
Använd detta alternativ endast när applikationen har en avsiktlig händelsebaserad felmodell, eftersom den anropande koden inte längre ser något undantag. Fel med svårighetsgrad 17 eller högre utlöser fortfarande SqlException. Sätt egenskapen en gång som en del av anslutningskonfigurationen istället för att växla den för enskilda kommandon.
Loggkontext för diagnostik
Fånga tillräckligt med strukturerad kontext för att korrelera felet utan att exponera data. Följande utdrag loggar namnet på en applikationsoperation, ClientConnectionId och fälten för varje SqlError.
ClientConnectionId hjälper till att koppla ett klientfel till server- och nätverksdiagnostik. Det är ingen legitimation.
const string operation = "LoadOrders";
using (var load = new SqlCommand("SELECT 1 / 0;", connection))
{
try
{
await load.ExecuteScalarAsync();
}
catch (SqlException exception)
{
Console.WriteLine(
$"Operation={operation}; " +
$"ClientConnectionId={exception.ClientConnectionId}");
foreach (SqlError error in exception.Errors)
{
Console.WriteLine(
$"Number={error.Number}; Class={error.Class}; " +
$"State={error.State}; Procedure={error.Procedure}; " +
$"Line={error.LineNumber}");
}
}
}
Värdet ClientConnectionId varierar på varje anslutning. Utdraget skriver ut utdata som liknar:
Operation=LoadOrders; ClientConnectionId=<connection ID>
Number=8134; Class=16; State=1; Procedure=; Line=1
Registrera också om en transaktion var aktiv och, om BatchCommand finns tillgängligt, vilket batchkommando som misslyckades. Inkludera sanerade server- och databasidentifierare endast om organisationens policy tillåter det. Logga inte anslutningssträngar, åtkomsttokens, lösenord eller känsliga parametervärden. Använd diagnostikräknare, spårning av händelsekällor och SqlClient-felsökningsguiden för djupare undersökningar.
Relaterat innehåll
- Gå tillbaka till arbetsflödet för kommandoexekvering.
- För att identifiera ett misslyckat kommando i en grupp, kör flera kommandon med SqlBatch.
- För att lägga till begränsade omförsök, använd konfigurerbar omförsökslogik.
- När undantagsfält inte räcker, använd SqlClients felsökningsguide.