Kilitlenmenin neden olduğu SqlException nasıl yakalanır?


94

Bir .NET 3.5 itibaren / C # uygulaması, ben catch istiyorum SqlExceptionama o çözümsüzlüklerle neden yalnızca SQL Server 2008 örneğinde.

Tipik hata mesajı Transaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

Yine de, bu istisna için belgelenmiş bir hata kodu gibi görünmemektedir .

Mesajlarında kilitlenme anahtar kelimesinin varlığına karşı istisnayı filtrelemek, bu davranışı gerçekleştirmenin çok çirkin bir yolu gibi görünüyor. Birisi bunu yapmanın doğru yolunu biliyor mu?


3
(Sonunda) hata kodunun belgelerini buldum: msdn.microsoft.com/en-us/library/aa337376.aspx . Bunu SQL Server'ın kendisinde de bulabilirsiniz:select * from master.dbo.sysmessages where error=1205
Martin McNulty,

Yanıtlar:


157

Bir kilitlenme için Microsft SQL Server'a özgü hata kodu 1205'tir, bu nedenle SqlException ile ilgilenmeniz ve bunu kontrol etmeniz gerekir. Öyleyse, örneğin diğer tüm SqlException türleri için balonun istisnanın yukarı olmasını istiyorsanız:

catch (SqlException ex)
{
    if (ex.Number == 1205)
    {
        // Deadlock 
    }
    else
        throw;
}

Veya C # 6'da bulunan istisna filtrelemeyi kullanarak

catch (SqlException ex) when (ex.Number == 1205)
{
    // Deadlock 
}

Verilen bir mesaj için gerçek SQL hata kodunu bulmak için yapılacak kullanışlı bir şey, SQL Server'daki sys.message'lara bakmaktır.

Örneğin

SELECT * FROM sys.messages WHERE text LIKE '%deadlock%' AND language_id=1033

Kilitlenmeleri işlemenin alternatif bir yolu (SQL Server 2005 ve üstü), bunu TRY ... CATCH desteğini kullanarak bir saklı yordam içinde yapmaktır:

BEGIN TRY
    -- some sql statements
END TRY
BEGIN CATCH
    IF (ERROR_NUMBER() = 1205)
        -- is a deadlock
    ELSE
        -- is not a deadlock
END CATCH

Burada MSDN'de, kilitlenme yeniden deneme mantığının tamamen SQL içinde nasıl uygulanacağına dair tam bir örnek var .


2
Hata kodlarının satıcıya özel olduğunu, bu nedenle
1205'in

3
Veri katmanına bağlı olarak, SqlExceptionbaşka bir katmana sarılmış olabilir. Bu nedenle, herhangi bir istisna türünü yakalamamız ve kontrol etmemiz gerekebilir, ardından doğrudan bir kilitlenme istisnası değilse, tekrar tekrar kontrol edin InnerException.
Frédéric

46

Sanırım kilitlenmeleri tespit etmek isteyebilirsiniz, başarısız olan işlemi yeniden denemek için, sizi küçük bir an için uyarmak isterim. Umarım burada biraz konu dışı kaldığım için beni affedersiniz.

Veritabanı tarafından algılanan bir kilitlenme, bağlantı .NET'te açık tutulurken, çalıştırdığınız işlemi (varsa) etkin bir şekilde geri alır. Bu işlemin (aynı bağlantıda) yeniden denenmesi, işlemsiz bir bağlamda yürütüleceği anlamına gelir ve bu, veri bozulmasına neden olabilir.

Bunun farkında olmak önemlidir. En iyisi, SQL'in neden olduğu bir arıza durumunda tüm bağlantıyı mahkum etmiş saymaktır. İşlemin yeniden denenmesi, yalnızca işlemin tanımlandığı seviyede yapılabilir (bu işlemi ve bağlantısını yeniden oluşturarak).

Bu nedenle, başarısız bir işlemi yeniden denediğinizde, lütfen tamamen yeni bir bağlantı açtığınızdan ve yeni bir işlem başlattığınızdan emin olun.


4
Neden tamamen yeni bir bağlantıya ihtiyacınız var? Burada bu cevapla ilgili bir soru yayınladım .
Sam

3

İşte kilitlenmeleri tespit etmenin bir C # 6 yolu.

try
{
    //todo: Execute SQL. 
    //IMPORTANT, if you used Connection.BeginTransaction(), this try..catch must surround that code. You must rollback the original transaction, then recreate it and re-run all the code.
}
catch (SqlException ex) when (ex.Number == 1205)
{
    //todo: Retry SQL
}

Bu try..catch'in tüm işleminizi çevrelediğinden emin olun. @Steven'e göre (ayrıntılar için cevabına bakın), kilitlenme nedeniyle sql komutu başarısız olduğunda, işlemin geri alınmasına neden olur ve işlemi yeniden oluşturmazsanız, yeniden denemeniz bağlam dışında yürütülür. işlem ve veri tutarsızlıklarına neden olabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.