Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Microsoft. Data.SqlClient rapporteert server- en providerstoringen via SqlException. Een databasebewerking kan meerdere fouten teruggeven, dus inspecteer de Errors verzameling van de uitzondering in plaats van alleen te vertrouwen op de gecombineerde Message.
Waarschuwingen en informatieve berichten van de database-engine worden doorgegeven via InfoMessage. Abonneer je voordat je de verbinding opent of het commando uitvoert dat het bericht kan genereren.
Behandel een databasefout in deze volgorde:
- Vang
SqlExceptionbij een grens die operationele context kan toevoegen of kies een herstelactie. - Controleer elke
SqlErrorin deErrorscollectie. - Registreer gestructureerde diagnostische velden zonder inloggegevens of gevoelige waarden vast te leggen.
- Controleer de verbindingsstatus na een verbindingsgerelateerde storing.
- Probeer het alleen opnieuw wanneer de fout tijdelijk is en de bewerking veilig is om te herhalen.
In de voorbeelden in dit artikel wordt ervan uitgegaan dat een open SqlConnection met de naam connection gericht is op de AdventureWorks-voorbeelddatabase. De C#-voorbeelden vereisen using Microsoft.Data.SqlClient;.
Ontvang informatieve berichten
Het InfoMessage event ontvangt serverberichten met lage ernst, inclusief output van PRINT. Eén gebeurtenis kan meerdere SqlError objecten bevatten. Abonneer je voordat je het commando uitvoert dat een bericht kan genereren:
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();
Het fragment toont:
Info 0, class 0: Connected and ready.
Catch SqlException
Vang SqlException om de database-operatie heen die je kunt beheren of verrijken. Gebruik geen algemene catch om een mislukte databaseoperatie om te zetten in een succesvol resultaat.
Een databasebewerking kan meer dan één fout teruggeven. Elke SqlError in Errors omvat gestructureerde velden:
| Property | Meaning |
|---|---|
Number |
Foutnummer van database-engine of provider. |
Class |
Ernstniveau. |
State |
Server-gedefinieerde toestand die locaties kan onderscheiden voor hetzelfde foutnummer. |
LineNumber |
Gemeld regelnummer |
Procedure |
Naam van procedure of trigger wanneer aangeleverd. |
Server |
Servernaam gerapporteerd bij de fout. |
Message |
Leesbare fouttekst. |
De gemakseigenschappen op SqlException, waaronder Number, Class, , State, LineNumber, Procedure, en Server, weerspiegelen alleen de eerste fout. Het volgende fragment drukt een bericht af en genereert vervolgens een fout in dezelfde batch. Het leest exception.Number en itereert vervolgens over Errors om elke invoer te rapporteren:
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}");
}
}
}
Het fragment luidt:
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.
De PRINT output verhoogt InfoMessageniet. Wanneer een batch een foutmelding geeft die SqlException veroorzaakt, voegt de provider de informatieve berichten van die batch toe aan het einde van SqlException.Errors.
Dit fragment vangt de gecontroleerde fout alleen op om de velden ervan te tonen. In applicatiecode: werp opnieuw op met throw;, tenzij het catchblok voor daadwerkelijk herstel kiest. Neem beslissingen op basis van gedocumenteerde foutnummers en de operationele context. Parse geen gelokaliseerde berichttekst.
De verbindingsstatus controleren
De database-engine wijst aan elk bericht een ernstklasse toe. Subklassen zijn informatief. Klassen die als fouten worden behandeld, produceren SqlException. Fouten met hoge ernst kunnen de verbinding sluiten of verbreken.
Controleer na een foutmelding State voordat je de verbinding opnieuw gebruikt:
using var command = new SqlCommand(
"RAISERROR (N'Controlled failure.', 16, 1);",
connection);
try
{
command.ExecuteNonQuery();
}
catch (SqlException)
{
Console.WriteLine($"Connection state: {connection.State}");
}
Ga er niet van uit dat een verbinding bruikbaar blijft omdat de uitzondering is opgevangen. Een fout van ernst 16 laat het meestal open, maar fouten die de verbinding verbreken kunnen het sluiten. Geef een gesloten of verbroken verbinding vrij en haal een andere verbinding uit de pool. Codeer het beleid voor nieuwe pogingen niet alleen op basis van de ernst. De operatie moet ook veilig herhaald kunnen worden.
Identificeer een mislukte batchopdracht
Wanneer een SqlBatch faalt, kan SqlException.BatchCommand naar de bijbehorende SqlBatchCommand verwijzen. De eigenschap is null wanneer de provider de mislukking niet aan één batchcommando kan toeschrijven. Het volgende fragment bevat twee batchcommando's. De tweede mislukt:
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}");
}
}
}
Het fragment geeft weer:
Error 8134: Divide by zero error encountered.
Failed command: SELECT 1 / 0;
Commandotekst kan gevoelige literals bevatten in slecht geparametriseerde applicaties. Geef de voorkeur aan stabiele applicatiebewerkingsnamen in productielogs en log standaard geen parameterwaarden.
Stuur gebruikersfouten naar InfoMessage
FireInfoMessageEventOnUserErrors wordt standaard ingesteld op false. Wanneer je het instelt op true, gaan fouten met ernst 16 of lager naar de InfoMessage-handler in plaats van SqlException te genereren:
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();
Er wordt geen uitzondering opgeworpen. Het fragment geeft het volgende weer:
Info 50000, class 16: Routed to InfoMessage.
Gebruik deze optie alleen wanneer de applicatie een bewust event-based foutmodel heeft, omdat de aanroepende code geen uitzondering meer ziet. Fouten met ernst 17 of hoger geven nog steeds SqlException. Stel de eigenschap één keer in als onderdeel van de verbindingsconfiguratie in plaats van deze voor en na afzonderlijke opdrachten in en uit te schakelen.
Diagnostische logcontext
Leg voldoende gestructureerde context vast om de mislukking te correleren zonder data bloot te stellen. Het volgende fragment registreert een applicatie-operatienaam, de ClientConnectionId, en de velden van elke SqlError.
ClientConnectionId Helpt een clientstoring te correleren met server- en netwerkdiagnostiek. Het is geen inloggegeven.
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}");
}
}
}
De ClientConnectionId waarde verschilt per verbinding. Het fragment geeft vergelijkbare uitvoer weer als volgt:
Operation=LoadOrders; ClientConnectionId=<connection ID>
Number=8134; Class=16; State=1; Procedure=; Line=1
Noteer ook of een transactie actief was en, indien BatchCommand beschikbaar, welk batchcommando is mislukt. Voeg alleen gesaniteerde server- en database-identificaties toe als het organisatiebeleid dit toestaat. Log geen verbindingsstrings, toegangstokens, wachtwoorden of gevoelige parameterwaarden. Gebruik diagnostische tellers, event source tracing en de SqlClient probleemoplossingsgids voor dieper onderzoek.
Verwante onderwerpen
- Keer terug naar de workflow voor het uitvoeren van commando's.
- Om een mislukt commando in een groep te identificeren, voer je meerdere commando's uit met SqlBatch.
- Om begrensde herpogingen toe te voegen, gebruik configureerbare herpogingslogica.
- Als uitzonderingsvelden niet genoeg zijn, gebruik dan de SqlClient probleemoplossingsgids.