Mam procedurę składowaną, która wykonuje w niej tylko 3 procedury składowane. Używam tylko 1 parametru do przechowywania, jeśli główny SP jest udany.
Jeśli pierwsza procedura przechowywana działa poprawnie w głównej procedurze przechowywanej, ale druga procedura przechowywana nie powiedzie się, to czy automatycznie przywróci wszystkie SP w głównej SP, czy muszę wykonać jakieś polecenie?
Oto moja procedura:
CREATE PROCEDURE [dbo].[spSavesomename]
-- Add the parameters for the stored procedure here
@successful bit = null output
AS
BEGIN
begin transaction createSavebillinginvoice
begin Try
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN
EXEC [dbo].[spNewBilling1]
END
BEGIN
EXEC [dbo].[spNewBilling2]
END
BEGIN
EXEC [dbo].[spNewBilling3]
END
set @successful = 1
end Try
begin Catch
rollback transaction createSavesomename
insert into dbo.tblErrorMessage(spName, errorMessage, systemDate)
values ('spSavesomename', ERROR_MESSAGE(), getdate())
return
end Catch
commit transaction createSavesomename
return
END
GO
sql-server
stored-procedures
transaction
użytkownik2483342
źródło
źródło
spNewBilling3
zgłasza błąd, ale nie chcesz wycofaćspNewBilling2
lubspNewBilling1
, po prostu usuń[begin|rollback|commit] transaction createSavebillinginvoice
zspSavesomename
.Odpowiedzi:
Biorąc pod uwagę tylko kod pokazany w pytaniu, a przy założeniu, że żaden z trzech sub-proca nie lada obsługa transakcja jawne, to tak, błąd w którymkolwiek z trzech sub-proca zostanie złapany, a
ROLLBACK
wCATCH
bloku przywróci wszystko z pracy.ALE oto kilka rzeczy na temat transakcji (przynajmniej w SQL Server):
Jest tylko jedna prawdziwa transakcja (pierwsza), bez względu na to, ile razy dzwonisz
BEGIN TRAN
BEGIN TRAN
, niezależnie od tego, czy jest nazwany, licznik transakcji jest zwiększany o 1.SELECT @@TRANCOUNT;
COMMIT
polecenia wydane, gdy@@TRANCOUNT
jest na poziomie 2 lub wyższym, nie robią nic więcej niż zmniejszają, pojedynczo, licznik transakcji.COMMIT
zostanie wydane, gdy@@TRANCOUNT
jest w1
Punkty zapisu pozwalają na utworzenie podzbioru pracy w ramach transakcji, który można cofnąć.
SAVE TRAN {save_point_name}
poleceniaROLLBACK {save_point_name}
. (więcej na ten temat poniżej)SAVE TRAN {save_point_name}
, w tym wszystkich punktów zapisu utworzonych po utworzeniu wycofanego punktu (stąd „zagnieżdżanie”).SAVE TRAN
nie mogą zostać cofnięte, chyba że wydane zostaną pełneROLLBACK
transakcje.COMMIT
kiedy@@TRANCOUNT
jest na poziomie 2 lub wyższym, nie ma wpływu na punkty zapisu (ponieważ ponownie poziomy transakcji powyżej 1 nie istnieją poza tym licznikiem).Nie można zatwierdzać określonych nazwanych transakcji. „Nazwa” transakcji, jeśli jest podana wraz z
COMMIT
, jest ignorowana i istnieje tylko dla czytelności.ROLLBACK
Wydawane bez nazwy zawsze będzie wycofać wszystkie transakcje.ROLLBACK
Wydane z nazwa musi odpowiadać albo:Zakładając, że nie
SAVE TRAN
została wywołana żadna z tą samą nazwą transakcji, spowoduje to wycofanie WSZYSTKICH transakcji.To zachowanie spowoduje „cofnięcie” wszystkich zmian wprowadzonych od czasu wywołania ostatniego
SAVE TRAN {save_point_name}
.SAVE TRAN
wydano komendy z jej nazwą, to każde ROLLBACK tej nazwy transakcji cofnie każdy punkt zapisu, dopóki nie pozostanie żadna z tej nazwy. Następnie wydany ROLLBACK o tej nazwie przywróci WSZYSTKIE transakcje.Załóżmy na przykład, że następujące polecenia zostały uruchomione w pokazanej kolejności:
Teraz, jeśli wydajesz (każdy z poniższych scenariuszy jest od siebie niezależny):
ROLLBACK TRAN B
jeden raz: Cofa „DML Query 4”.@@TRANCOUNT
jest nadal 2.ROLLBACK TRAN B
dwa razy: Cofa „DML Query 4”, a następnie błąd, ponieważ nie ma odpowiedniego punktu zapisu dla „B”.@@TRANCOUNT
jest nadal 2.ROLLBACK TRAN A
jeden raz: Cofnie „DML Query 4” i „DML Query 3”.@@TRANCOUNT
jest nadal 2.ROLLBACK TRAN A
dwa razy: Cofa „DML Query 4”, „DML Query 3” i „DML Query 2”.@@TRANCOUNT
jest nadal 2.ROLLBACK TRAN A
trzy razy: Cofnie „DML Query 4”, „DML Query 3” i „DML Query 2”. Następnie cofnie całą transakcję (pozostało tylko „DML Query 1”).@@TRANCOUNT
jest teraz 0.COMMIT
jeden raz:@@TRANCOUNT
spada do 1.COMMIT
raz, a potemROLLBACK TRAN B
raz:@@TRANCOUNT
spada do 1. Następnie cofnie „DML Query 4” (udowadniając, że COMMIT nic nie zrobił).@@TRANCOUNT
jest nadal 1.Nazwy transakcji i nazwy punktów zapisu:
Procedura przechowywana sama w sobie nie jest transakcją niejawną. Każde zapytanie, jeśli żadna jawna transakcja nie została rozpoczęta, jest transakcją niejawną. Z tego powodu jawne transakcje wokół pojedynczych zapytań nie są konieczne, chyba że istnieje powód programowy
ROLLBACK
, w przeciwnym razie każdy błąd w zapytaniu jest automatycznym wycofywaniem tego zapytania.Podczas wywoływania procedury składowanej musi wyjść z wartością
@@TRANCOUNT
bycia taką samą, jak w momencie jej wywołania. Oznacza to, że nie możesz:BEGIN TRAN
w proc, nie popełniając jej, oczekując zatwierdzenia w procesie wywołującym / nadrzędnym.ROLLBACK
jeśli jawna transakcja została uruchomiona przed wywołaniem proc, ponieważ powróci ona@@TRANCOUNT
do zera.Jeśli wyjdziesz z procedury składowanej z liczbą transakcji, która jest albo wyższa, albo niższa niż wtedy, gdy się zapatrzyła, pojawi się błąd podobny do:
Zmienne tabelowe, podobnie jak zmienne zwykłe, nie są powiązane transakcjami.
Odnośnie obsługi transakcji w procesach, które mogą być wywoływane niezależnie (a zatem wymagają obsługi transakcji) lub połączenia z innych procedur (stąd nie wymagają obsługi transakcji): można to zrobić na kilka różnych sposobów.
Sposób, w jaki sobie z tym radzę od kilku lat, który wydaje się działać dobrze, to tylko
BEGIN
/COMMIT
/ROLLBACK
w najbardziej zewnętrznej warstwie. Wywołania sub-proc po prostu pomijają polecenia transakcji. Poniżej nakreśliłem, co wkładam w każdy proces (cóż, każdy, który wymaga obsługi transakcji).DECLARE @InNestedTransaction BIT;
Zamiast prostego
BEGIN TRAN
wykonaj:Zamiast prostego
COMMIT
wykonaj:Zamiast prostego
ROLLBACK
wykonaj:Ta metoda powinna działać tak samo, niezależnie od tego, czy transakcja została uruchomiona w programie SQL Server, czy w warstwie aplikacji.
Pełny szablon obsługi transakcji w ramach
TRY...CATCH
konstruktu znajduje się w mojej odpowiedzi na następujące pytanie DBA.SE: Czy jesteśmy zobowiązani do obsługi transakcji w kodzie C #, jak również w procedurze przechowywanej .Wychodząc poza „podstawy”, istnieją pewne dodatkowe niuanse transakcji, o których należy pamiętać:
Domyślnie transakcje przez większość czasu nie są automatycznie wycofywane / anulowane po wystąpieniu błędu. Zwykle nie stanowi to problemu, o ile masz odpowiednią obsługę błędów i zadzwonisz do
ROLLBACK
siebie. Czasami jednak sprawy się komplikują, na przykład w przypadku błędów przerywających wsad lub podczas korzystaniaOPENQUERY
(lub ogólnie z połączonych serwerów) i błąd występuje w systemie zdalnym. Chociaż większość błędów można złapać w pułapkę za pomocąTRY...CATCH
, są dwa, których nie można złapać w ten sposób (chociaż nie pamiętam, które z nich w tej chwili - badanie). W takich przypadkach musisz użyć,SET XACT_ABORT ON
aby poprawnie wycofać transakcję.Ustawienie XACT_ABORT ON powoduje, że SQL Server natychmiast wycofuje dowolną transakcję (jeśli jest aktywna) i przerywa partię, jeśli wystąpi jakikolwiek błąd. To ustawienie istniało przed SQL Server 2005, który wprowadził
TRY...CATCH
konstrukcję. W przeważającej częściTRY...CATCH
obsługuje większość sytuacji, a więc w większości przypadków przestaje istnieć taka potrzebaXACT_ABORT ON
. Jednak podczas korzystaniaOPENQUERY
(i prawdopodobnie jednego innego scenariusza, którego obecnie nie pamiętam), nadal będziesz musiał go użyćSET XACT_ABORT ON;
.Wewnątrz wyzwalacza
XACT_ABORT
jest domyślnie ustawiony naON
. Powoduje to, że każdy błąd w Triggerze anuluje całą instrukcję DML, która uruchomiła Trigger.Zawsze powinieneś mieć odpowiednią obsługę błędów, szczególnie podczas korzystania z Transakcji.
TRY...CATCH
Konstrukt, wprowadzony w SQL Server 2005, zapewnia środki do obsługi niemal wszystkich sytuacjach poprawę powitalny nad testowania dla@@ERROR
po każdej instrukcji, co nie pomogło z błędami wsadowych-przerywanie.TRY...CATCH
wprowadził jednak nowy „stan”. Jeśli nie używaszTRY...CATCH
konstrukcji, jeśli masz aktywną transakcję i wystąpi błąd, istnieje kilka ścieżek, które można podjąć:XACT_ABORT OFF
i błąd przerywania instrukcji: Transakcja jest nadal aktywna i przetwarzanie jest kontynuowane z następną instrukcją , jeśli taka istnieje.XACT_ABORT OFF
i większość błędów przerywania partii: Transakcja jest nadal aktywna i przetwarzanie jest kontynuowane z następną partią , jeśli taka istnieje.XACT_ABORT OFF
oraz niektóre błędy przerywania partii: Transakcja jest wycofywana, a przetwarzanie jest kontynuowane z następną partią , jeśli taka istnieje.XACT_ABORT ON
i każdy błąd: transakcja jest wycofywana, a przetwarzanie jest kontynuowane z następną partią , jeśli taka istnieje.JEDNAK podczas używania
TRY...CATCH
błędy przerywania partii nie przerywają partii, lecz przekazują kontrolę doCATCH
bloku. KiedyXACT_ABORT
to nastąpiOFF
, transakcja będzie nadal aktywna przez większość czasu i będziesz musiał to zrobićCOMMIT
, lub najprawdopodobniejROLLBACK
. Ale w przypadku napotkania pewnych błędów przerywania partii (takich jak zOPENQUERY
) lub kiedyXACT_ABORT
jestON
, transakcja będzie w nowym stanie, „niekomfortowym”. W tym stanie nie możeszCOMMIT
ani nie możesz wykonywać żadnych operacji DML. Wszystko, co można zrobić, toROLLBACK
iSELECT
oświadczenia. Jednak w tym „nieprzyzwoitym” stanie transakcja została wycofana po wystąpieniu błędu, a wydanieROLLBACK
jest tylko formalnością, ale należy ją wykonać.Funkcja XACT_STATE może być użyta do ustalenia, czy transakcja jest aktywna, niekomfortowa lub nie istnieje. Zaleca się (przynajmniej przez niektórych), aby sprawdzić tę funkcję w
CATCH
bloku, aby ustalić, czy wynik jest-1
(tj. Niekomfortowy) zamiast testować, czy@@TRANCOUNT > 0
. Ale zXACT_ABORT ON
, powinien to być jedyny możliwy stan, więc wydaje się, że testowanie@@TRANCOUNT > 0
iXACT_STATE() <> 0
są równoważne. Z drugiej strony, kiedyXACT_ABORT
jestOFF
i jest aktywna Transakcja, wówczas możliwe jest posiadanie stanu jednego z nich1
lub jeśli Transakcja jest możliwa do zatwierdzenia). Więcej informacji i badań na temat używania w bloku z można znaleźć w mojej odpowiedzi na następujące pytanie DBA.SE:-1
wCATCH
bloku, co pozwala na możliwość wydaniaCOMMIT
zamiastROLLBACK
(chociaż nie mogę wymyślić przypadku, w którym ktoś chciałbymCOMMIT
XACT_STATE()
CATCH
XACT_ABORT ON
W jakich przypadkach transakcja może zostać zatwierdzona z bloku CATCH, gdy XACT_ABORT jest ustawiony na ON? . Należy pamiętać, że istnieje niewielki błąd,XACT_STATE()
który powoduje, że1
w niektórych scenariuszach zwraca on błąd : XACT_STATE () zwraca 1, gdy jest używany w SELECT z niektórymi zmiennymi systemowymi, ale bez klauzuli FROMUwagi na temat oryginalnego kodu:
BEGIN
iEND
wokół każdegoEXEC
połączeniaźródło
Compile errors, such as syntax errors, that prevent a batch from running
iErrors that occur during statement-level recompilation, such as object name resolution errors that occur after compilation because of deferred name resolution.
. Ale nie zdarzają się zbyt często, a gdy znajdziesz taką sytuację, napraw ją (jeśli jest to błąd w kodzie) lub umieść w podprocesie (EXEC
lubsp_executesql
), abyTRY...CATCH
ją zatrzymać.Tak, jeśli z powodu jakiegokolwiek błędu przywracania kodu w instrukcji catch głównej procedury przechowywanej zostanie wykonane, spowoduje to wycofanie wszystkich operacji wykonanych przez dowolną instrukcję bezpośrednią lub dowolną z zagnieżdżonych w niej procedur przechowywanych.
Nawet jeśli nie zastosowałeś żadnej jawnej transakcji w zagnieżdżonych procedurach przechowywanych, nadal ta procedura przechowywana będzie korzystać z transakcji niejawnych i zostanie zatwierdzona po zakończeniu, ALE albo dokonałeś transakcji jawnej lub niejawnej w zagnieżdżonych procedurach przechowywanych Silnik SQL Server zignoruje to i będzie wycofaj wszystkie działania tych zagnieżdżonych procedur przechowywanych, jeśli główna procedura przechowywana nie powiedzie się, a transakcja zostanie wycofana.
Za każdym razem, gdy transakcja jest zatwierdzana lub wycofywana w oparciu o działania podjęte na końcu najbardziej zewnętrznej transakcji. Jeśli transakcja zewnętrzna zostanie zatwierdzona, transakcje wewnętrzne zagnieżdżone również zostaną zatwierdzone. Jeśli transakcja zewnętrzna zostanie wycofana, wszystkie transakcje wewnętrzne również zostaną wycofane, niezależnie od tego, czy transakcje wewnętrzne zostały indywidualnie zatwierdzone.
W celach informacyjnych http://technet.microsoft.com/en-us/library/ms189336(v=sql.105).aspx
źródło