Z aplikacji .NET 3.5 / C # chciałbym wychwycić, SqlException
ale tylko wtedy, gdy jest to spowodowane zakleszczeniami w wystąpieniu SQL Server 2008.
Typowy komunikat o błędzie to Transaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
Jednak nie wydaje się, aby był to udokumentowany kod błędu dla tego wyjątku.
Filtrowanie wyjątku od obecności słowa kluczowego zakleszczenia w ich wiadomości wydaje się być bardzo brzydkim sposobem osiągnięcia tego zachowania. Czy ktoś wie, jak to zrobić?
.net
sql-server-2008
deadlock
try-catch
sqlexception
Joannes Vermorel
źródło
źródło
select * from master.dbo.sysmessages where error=1205
Odpowiedzi:
Kod błędu specyficzny dla Microsft SQL Server dla zakleszczenia to 1205, więc musisz obsłużyć SqlException i sprawdzić to. Na przykład, jeśli dla wszystkich innych typów SqlException chcesz, aby bąbelek wyjątek był górny:
Lub używając filtrowania wyjątków dostępnego w C # 6
Przydatną rzeczą do znalezienia rzeczywistego kodu błędu SQL dla danej wiadomości jest zajrzenie do sys.messages w SQL Server.
na przykład
SELECT * FROM sys.messages WHERE text LIKE '%deadlock%' AND language_id=1033
Alternatywnym sposobem obsługi zakleszczeń (z SQL Server 2005 i nowszych) jest zrobienie tego w ramach procedury składowanej przy użyciu obsługi TRY ... CATCH:
BEGIN TRY -- some sql statements END TRY BEGIN CATCH IF (ERROR_NUMBER() = 1205) -- is a deadlock ELSE -- is not a deadlock END CATCH
Jest to pełny przykład tutaj w MSDN sposobu realizacji zakleszczenia logikę ponawiania wyłącznie wewnątrz SQL.
źródło
SqlException
może być opakowana w inną. Może więc być konieczne złapanie dowolnego rodzaju wyjątku i sprawdzenie go, a następnie, jeśli nie są bezpośrednio wyjątkiem zakleszczenia, rekurencyjnie sprawdź ichInnerException
.Ponieważ przypuszczam, że prawdopodobnie chcesz wykryć zakleszczenia, aby móc ponowić nieudaną operację, chciałbym Cię ostrzec, żebyś się trochę zorientował. Mam nadzieję, że wybaczycie mi, że jestem tu trochę poza tematem.
Zakleszczenie wykryte przez bazę danych skutecznie wycofa transakcję, w której byłeś uruchomiony (jeśli wystąpiła), podczas gdy połączenie jest otwarte w .NET. Ponawianie tej operacji (w tym samym połączeniu) oznacza, że zostanie ona wykonana w kontekście bez transakcji, co może prowadzić do uszkodzenia danych.
Należy być tego świadomym. Najlepiej jest uznać, że całe połączenie jest skazane na porażkę w przypadku awarii spowodowanej przez SQL. Ponawianie operacji można wykonać tylko na poziomie, na którym transakcja jest zdefiniowana (poprzez odtworzenie tej transakcji i jej połączenia).
Więc kiedy ponawiasz nieudaną operację, upewnij się, że otworzyłeś zupełnie nowe połączenie i rozpocznij nową transakcję.
źródło
Oto sposób wykrywania zakleszczeń w języku C # 6.
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 }
Upewnij się, że ta try..catch otacza całą transakcję. Według @Stevena (zobacz jego odpowiedź po szczegóły), gdy polecenie sql nie powiedzie się z powodu zakleszczenia, powoduje to wycofanie transakcji, a jeśli nie utworzysz ponownie transakcji, ponowna próba zostanie wykonana poza kontekstem transakcji i może skutkować niespójnością danych.
źródło