Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Microsoft. Data.SqlClient hlásí selhání serveru a poskytovatele prostřednictvím SqlException. Databázová operace může vrátit více chyb, proto kontrolujte kolekci výjimky Errors místo spoléhání se pouze na kombinovanou zprávu Message.
Varování a informační zprávy z databázového enginu jsou doručovány prostřednictvím InfoMessage. Přihlaste se k odběru před otevřením spojení nebo vykonáním příkazu, který může zprávu vygenerovat.
Řešit selhání databáze v tomto pořadí:
- Zachyťte
SqlExceptionna hranici, která může přidat kontext operace nebo zvolit akci pro obnovení. - Prohlédněte si všechny
SqlErrorv kolekciErrors. - Zaznamenávejte strukturovaná diagnostická pole bez zaznamenávání přihlašovacích údajů nebo citlivých hodnot.
- Zkontrolujte stav připojení po selhání souvisejícím s připojením.
- Opakujte to pouze tehdy, když je chyba přechodná a operace je bezpečná k opakování.
Příklady v tomto článku předpokládají, že otevřené SqlConnection s názvem connection cílí na ukázkovou databázi AdventureWorks. Příklady v C# vyžadují using Microsoft.Data.SqlClient;.
Přijímat informační zprávy
Událost InfoMessage přijímá serverové zprávy s nízkou závažností, včetně výstupu z PRINT. Jedna událost může obsahovat více SqlError objektů. Před vykonáním příkazu, který může vygenerovat zprávu, se přihlaste k odběru zpráv:
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();
Výňatek se vytiskne:
Info 0, class 0: Connected and ready.
Catch SqlException
Zachyťte SqlException kolem databázové operace, kterou můžete zpracovat nebo rozšířit o další informace. Nepoužívejte obecné zachycení výjimky k proměně neúspěšné databázové operace v úspěšný výsledek.
Databázová operace může vrátit více než jednu chybu. Každý SqlError v Errors zahrnuje strukturovaná pole:
| Property | Meaning |
|---|---|
Number |
Číslo chyby databázového motoru nebo poskytovatele. |
Class |
Závažnost |
State |
Stav definovaný serverem, který dokáže rozlišit umístění pro stejné chybové číslo. |
LineNumber |
Číslo nahlášeného řádku. |
Procedure |
Postup nebo název spouštěče, je-li zadán. |
Server |
Název serveru nahlášený pro chybu. |
Message |
Chybový text čitelný pro člověka. |
Pomocné vlastnosti na SqlException, včetně Number, Class, State, LineNumber, Procedure a Server, odrážejí pouze první chybu. Následující úryvek vytiskne zprávu a poté vyvolá chybu ve stejné dávce. Čte exception.Number a poté iteruje Errors , aby nahlásil každý záznam:
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}");
}
}
}
Výňatek tiskne:
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.
Výstup PRINT nespustí InfoMessage. Když dávka vrátí chybu, která vyvolá SqlException, poskytovatel přidá informační zprávy této dávky na konec SqlException.Errors.
Tento úryvek zachytává kontrolovanou chybu pouze pro zobrazení jejích polí. V aplikačním kódu znovu vyvolejte výjimku pomocí throw;, pokud blok catch neprovádí skutečnou nápravnou akci. Rozhodujte se na základě zdokumentovaných čísel chyb a kontextu provozu. Neanalyzujte lokalizovaný text zpráv.
Zkontrolujte stav připojení
Databázový engine přiřazuje každé zprávě třídu závažnosti. Nižší třídy jsou informativní. Třídy považované za chyby vedou k SqlException. Chyby s vysokou závažností mohou ponechat spojení uzavřené nebo nefunkční.
Po chybě zkontrolujte State , než připojení znovu použijete:
using var command = new SqlCommand(
"RAISERROR (N'Controlled failure.', 16, 1);",
connection);
try
{
command.ExecuteNonQuery();
}
catch (SqlException)
{
Console.WriteLine($"Connection state: {connection.State}");
}
Nepředpokládejte, že spojení zůstává použitelné jen proto, že byla zachycena výjimka. Chyba závažnosti 16 ho obvykle ponechá otevřené, ale selhání přerušující spojení ho mohou uzavřít. Zlikvidujte uzavřené nebo přerušené připojení a získejte další připojení z poolu. Nekódujte politiku opakování jen podle závažnosti. Operace musí být také bezpečná k opakování.
Identifikace neúspěšného dávkového příkazu
Když selže SqlBatch, SqlException.BatchCommand může odkazovat na příslušnou SqlBatchCommand. Vlastnost je null, když poskytovatel nemůže přiřadit selhání jednomu dávkovému příkazu. Následující úryvek spouští dva dávkové příkazy. Druhý selže:
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}");
}
}
}
Úryvek vypíše:
Error 8134: Divide by zero error encountered.
Failed command: SELECT 1 / 0;
Text příkazu může obsahovat citlivé literály v špatně parametrizovaných aplikacích. Preferujte stabilní názvy operací aplikací v produkčních logech a nelogujte hodnoty parametrů ve výchozím nastavení.
Směrovat uživatelské chyby do InfoMessage
Výchozí hodnotou FireInfoMessageEventOnUserErrors je false. Když nastavíte true, chyby se závažností 16 nebo nižší přejdou do obslužné rutiny InfoMessage místo vyvolání 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();
Není vyvolána žádná výjimka. Výňatek tiskne:
Info 50000, class 16: Routed to InfoMessage.
Tuto možnost používejte pouze tehdy, když má aplikace záměrný model chyb založený na událostech, protože volací kód již výjimku nevidí. Chyby s vážností 17 nebo vyšší stále vyvolají SqlException. Nastavte vlastnost jednou jako součást konfigurace připojení, místo abyste ji přepínali u jednotlivých příkazů.
Kontext diagnostického protokolování
Zachyťte dostatek strukturovaného kontextu, aby bylo možné určit souvislost se selháním bez zpřístupnění dat. Následující úryvek zaznamenává název aplikační operace, ClientConnectionId, a pole každého SqlError.
ClientConnectionId Pomáhá to spojit selhání klienta s diagnostikou serveru a sítě. Není to žádný přihlašovací údaj.
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}");
}
}
}
Hodnota ClientConnectionId se liší u každého připojení. Ukázka vypíše výstup podobný:
Operation=LoadOrders; ClientConnectionId=<connection ID>
Number=8134; Class=16; State=1; Procedure=; Line=1
Také zaznamenat, zda byla transakce aktivní a pokud je BatchCommand k dispozici, který dávkový příkaz selhal. Uvádějte sanitizované identifikátory serverů a databází pouze tehdy, pokud to organizační politika umožňuje. Nezaznamenávejte spojovací řetězce, přístupové tokeny, hesla ani hodnoty citlivých parametrů. Pro hlubší zkoumání použijte čítače výkonu, trasování EventSource a průvodce SqlClient pro řešení problémů.
Související obsah
- Vraťte se k pracovnímu postupu spuštění příkazů.
- Pro identifikaci neúspěšného příkazu ve skupině spusťte více příkazů pomocí SqlBatch.
- Pro přidání omezených pokusů použijte konfigurovatelnou logiku opakovaných pokusů.
- Když pole výjimek nestačí, použijte průvodce řešením problémů SqlClient.