2015-05-17 9 views
6

Mam wyzwalacz INSERT w jednej z moich tabel, która powoduje WYKRES, gdy znajdzie duplikat. Problem polega na tym, że moje transakcje wydają się niejawnie wycofane w tym momencie - jest to problem, który chcę kontrolować po wycofaniu transakcji.Serwer SQL Przywraca moją transakcję podczas używania narzędzia Throw

Problem może być ponownie utworzone z tego skryptu:

CREATE TABLE xTable (
     id int identity not null 
) 
go 
create trigger xTrigger on xTable after insert as 
print 'inserting...'; 
throw 1600000, 'blah', 1 
go 

begin tran 
insert into xTable default values 
rollback tran 

go 
drop table xTable 

Po uruchomieniu Tran wycofywania - powie to nie ma się rozpocząć tran.

Jeśli zamieniam opcję RZUĆ na "normalny" wyjątek (np. SELECT 1/0), transakcja nie zostanie wycofana.

Sprawdziłem flagę xact_abort - i jest wyłączona.

Korzystanie z SQL Server 2012 i testowanie przez SSMS

Każda pomoc mile widziane, dzięki.

EDIT Po przeczytaniu artykułów napisanych przez @Dan Guzman, doszedłem do następującego wniosku/Podsumowując ...

SQL Server automatycznie ustawia XACT_ABORT ON w wyzwalaczy.

Mój przykład (powyżej) nie ilustruje mojej sytuacji - W rzeczywistości tworzę rozszerzone ograniczenie za pomocą wyzwalacza.

Mój przypadek użycia był wymyślony, próbowałem przetestować wiele sytuacji w teście jednostkowym SAME (nie jest to prawdziwa sytuacja na świecie, a NIE dobra praktyka testów jednostkowych).

Moje postępowanie z rozszerzoną kontrolą ograniczenia i zgłoszenie błędu w wyzwalaczu jest poprawne, jednak nie ma rzeczywistej sytuacji, w której nie chciałbym wycofywać transakcji.

Może być użyteczne USTAWIENIE XACT_ABORT OFF wewnątrz wyzwalacza dla określonego przypadku; ale twoja transakcja wciąż będzie podważana przez ogólne błędy przerwania partii (np. zakleszczenia).

Na marginesie, nie zgadzam się z obsługą SQL Server; tylko dlatego, że nie ma obecnej sytuacji, w której chciałbyś kontynuować transakcję, nie oznacza, że ​​taka sytuacja może nie wystąpić. Chciałbym, aby jeden mógł skonfigurować program SQL Server w celu zachowania integralności transakcji, jeśli wybrana architektura ma mieć transakcje ściśle zarządzane na początku, tj. "Tylko on, który rozpoczyna transakcję, musi ją zakończyć". To, poza zwykłymi awariami awaryjnymi, np. jeśli twój kod nigdy nie zostanie osiągnięty z powodu awarii systemu, itp.

Odpowiedz

4

THROW zakończy tę partię, gdy wykracza poza zakres TRY/CATCH (https://msdn.microsoft.com/en-us/library/ee677615.aspx). Implikacja polega na tym, że nie ma miejsca dalsze przetwarzanie tej partii, w tym instrukcje następujące po wstawieniu. Będziesz musiał otoczyć swoje urządzenie INSERT za pomocą TRY/CATCH lub użyć RAISERROR zamiast THROW.

Ręczne przekazywanie błędów T-SQL jest dość obszernym i złożonym tematem. Proponuję przeczytać serię artykułów do obsługi błędów autorstwa Erland Sommarskog: http://www.sommarskog.se/error_handling/Part1.html. Najważniejszy tutaj jest temat Can I Prevent the Trigger from Rolling Back the Transaction?http://www.sommarskog.se/error_handling/Part3.html#Triggers. Z punktu widzenia najlepszych praktyk wynika, że ​​wyzwalacze nie są właściwym rozwiązaniem, jeśli egzekwujesz reguły biznesowe w wyzwalaczu bez wycofywania.

+0

Ładne artykuły - dziękuje Dan. @usr, wyzwalacze muszą być na poziomie DB, są częścią rozszerzonych ograniczeń. W systemie z wieloma klientami (w tym SSIS), nie można egzekwować czeku wszędzie. Mój przykład nie podał wszystkich szczegółów sprawdzenia ograniczenia. Ani Dan, ani artykuł nie mówią, że nie powodują błędów w wyzwalaczu, mówią, że nie próbuj tłumić wycofywania. – Gilbert

Powiązane problemy