Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Microsoft.Data.SqlClient, sunucu ve sağlayıcı arızalarını SqlException aracılığıyla rapor eder. Bir veritabanı işlemi birden fazla hata döndürebilir, bu yüzden yalnızca birleşik Errors hatasına güvenmek yerine istisnanın Message koleksiyonunu inceleyin.
Veritabanı motorundan gelen uyarılar ve bilgilendirici mesajlar . InfoMessageüzerinden iletilmektedir. Bağlantıyı açmadan veya mesajı üretebilen komutu çalıştırmadan önce abone olun.
Veritabanı arızasını şu sırayla ele alın:
-
SqlExceptionöğesini, işlem bağlamı ekleyebilen bir sınırda yakalayın veya bir kurtarma eylemi seçin. -
SqlErrorkoleksiyonundaki herErrorsöğesini inceleyin. - Kimlik bilgileri veya hassas değerler kaydetmeden yapılandırılmış tanı alanlarını kaydedin.
- Bağlantıyla ilgili bir arızadan sonra bağlantı durumunu kontrol edin.
- Hata geçici olduğunda ve işlem tekrarlanabiliyorsa tekrar deneyin.
Bu makaledeki örnekler, connection adlı açık bir SqlConnection öğesinin AdventureWorks örnek veritabanını hedeflediğini varsaymaktadır. C# örnekleri using Microsoft.Data.SqlClient; gerektirir.
Bilgilendirici mesajlar alın
InfoMessage olayı, PRINT çıktısı dahil, düşük önem dereceli sunucu mesajlarını alır. Bir olay, birden fazla SqlError nesne içerebilir. Mesaj üretebilen komutu çalıştırmadan önce abone olun:
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();
Alıntı şunu yazdırır:
Info 0, class 0: Connected and ready.
Catch SqlException
Yönetebileceğiniz veya zenginleştirebileceğiniz veritabanı işleminin etrafında SqlException yakalayın. Başarısız bir veritabanı operasyonunu başarılı bir sonuca dönüştürmek için genel bir istisna yakalama kullanmayın.
Bir veritabanı işlemi birden fazla hata döndürebilir.
Errors içindeki her SqlError yapılandırılmış alanlar içerir:
| Özellik | Meaning |
|---|---|
Number |
Veritabanı motoru veya sağlayıcının hata numarası. |
Class |
Önem derecesi. |
State |
Aynı hata numarası için konumları ayırt edebilen sunucu tarafından tanımlanmış durum. |
LineNumber |
Hat numarası bildirildi. |
Procedure |
Prosedür veya tetikleyici adı verildiğinde. |
Server |
Hata için bildirilen sunucu adı. |
Message |
İnsan tarafından okunabilir hata metni. |
State üzerindeki, Number, Class, LineNumber, Procedure, Server ve SqlException dahil olmak üzere, kullanışlı özellikler yalnızca ilk hatayı yansıtır. Aşağıdaki alıntı bir mesaj yazdırır ve ardından aynı toplu işlemde bir hata fırlatır.
exception.Number okur ve ardından her girdiyi raporlamak için Errors üzerinde yineler:
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}");
}
}
}
Alıntı şunu yazdırır:
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.
Çıkış PRINTInfoMessage yükseltmiyor. Bir parti, SqlException oluşturan bir hata döndürdüğünde sağlayıcı o partinin bilgilendirici mesajlarını SqlException.Errors'nin sonuna ekler.
Bu alıntı, kontrollü hatayı yalnızca alanlarını göstermek için içerir. Uygulama kodunda, catch bloğu gerçek bir kurtarma eylemi seçmedikçe throw; ile yeniden atın. Belgelenmiş hata sayıları ve operasyon bağlamından karar verin. Yerel mesaj metnini ayrıştırmayın.
Bağlantı durumunu denetleyin
Veritabanı motoru her mesaja bir önem derecesi sınıfı atar. Alt sınıflar bilgilendirme amaçlıdır. Hata olarak ele alınan sınıflar SqlException üretir. Yüksek şiddetli hatalar bağlantıyı kapalı veya bozuk bırakabilir.
Bir hatadan sonra, bağlantıyı tekrar kullanmadan önce State denetleyin:
using var command = new SqlCommand(
"RAISERROR (N'Controlled failure.', 16, 1);",
connection);
try
{
command.ExecuteNonQuery();
}
catch (SqlException)
{
Console.WriteLine($"Connection state: {connection.State}");
}
İstisna yakalanmış olduğu için bağlantının kullanılabilir kaldığını varsaymayın. severity 16 hatası genellikle onu açık bırakır, ancak bağlantıyı kesen hatalar onu kapatabilir. Kapalı veya bozuk bir bağlantıyı serbest bırakın ve havuzdan başka bir bağlantı alın. Yeniden deneme politikasını yalnızca önem derecesine göre kodlamayın. İşlemin tekrarlanması da güvenli olmalıdır.
Başarısız bir toplu iş komutunu tespit edin
Bir SqlBatch başarısız olduğunda, SqlException.BatchCommand ilişkili SqlBatchCommand öğesine başvurabilir. Özellik, sağlayıcı başarısızlığı tek bir toplu komuta atfedemediğinde null olur. Aşağıdaki alıntı iki batch komutu içeriyor. İkincisi başarısız oluyor:
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}");
}
}
}
Alıntı şunu yazdırır:
Error 8134: Divide by zero error encountered.
Failed command: SELECT 1 / 0;
Komut metni, zayıf parametreli uygulamalarda hassas literaller içerebilir. Üretim günlüklerinde kararlı uygulama işlem adlarını tercih edin ve parametre değerlerini varsayılan olarak kaydetmeyin.
Kullanıcı hatalarını InfoMessage'a yönlendir
FireInfoMessageEventOnUserErrors varsayılan olarak false şeklinde ayarlanır. Bunu true olarak ayarladığınızda, 16 veya daha düşük önem derecesine sahip hatalar, InfoMessage oluşturmak yerine SqlException işleyicisine gider:
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();
İstisna atılmaz. Alıntı şunu yazdırır:
Info 50000, class 16: Routed to InfoMessage.
Bu seçeneği yalnızca uygulamanın kasıtlı olay tabanlı hata modeli olduğunda kullanın, çünkü çağıran kod artık istisna görmez. 17 veya daha yüksek şiddette hatalar yine de SqlException tetiklenir. Özelliği, tek tek komutlar için değiştirip durmak yerine bağlantı yapılandırmasının bir parçası olarak bir kez ayarlayın.
Log tanılama bağlamı
Başarısızlığı veri açığa çıkarmadan ilişkilendirecek kadar yapılandırılmış bağlam yakalayın. Aşağıdaki alıntı, bir uygulama işlem adını, ClientConnectionId ve her SqlError alanını kaydetmektedir.
ClientConnectionId İstemci arızasını sunucu ve ağ tanılamalarıyla ilişkilendirmeye yardımcı olur. Bu bir kimlik bilgisi değil.
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ğer ClientConnectionId her bağlantıda farklıdır. Alıntı aşağıdakine benzer bir çıktı yazdırır:
Operation=LoadOrders; ClientConnectionId=<connection ID>
Number=8134; Class=16; State=1; Procedure=; Line=1
Ayrıca bir işlemin aktif olup olmadığını ve BatchCommand varsa hangi toplu komutun başarısız olduğunu kaydedin. Temizlenmiş sunucu ve veritabanı tanımlayıcılarını yalnızca organizasyon politikası izin verirse ekleyin. Bağlantı dizilerini, erişim tokenlarını, şifreleri veya hassas parametre değerlerini kaydetmeyin. Daha derin inceleme için tanı sayaçları, olay kaynağı takibi ve SqlClient sorun giderme rehberini kullanın.
İlgili içerik
- Komut yürütme iş akışına geri dön.
- Bir grupta başarısız bir komutu belirlemek için SqlBatch ile birden fazla komut çalıştırın.
- Sınırlı denemeler eklemek için yapılandırılabilir yeniden deneme mantığı kullanın.
- İstisna alanları yeterli değilse, SqlClient sorun giderme rehberini kullanın.