Mam procedurę składowaną, która uruchamia kilka poleceń. Nie chcę, aby te polecenia były pakowane w transakcję procedury składowanej. Jeśli 4. polecenie nie powiedzie się, chcę, aby 1., 2. i 3. pozostały, a nie wycofały się.
Czy można zapisać procedurę składowaną w taki sposób, aby nie wszystkie były wykonywane jako jedna duża transakcja?
Wszystkie transakcje nie zostaną wykonane w jednej transakcji. Spójrz na ten przykład:
use TestDB;
go
ifexists(select1from sys.tables where object_id = object_id('dbo.TestTranTable1'))droptable dbo.TestTranTable1;createtable dbo.TestTranTable1
(
id int identity(1,1)notnull,
some_int int notnulldefault1);
go
insertinto dbo.TestTranTable1
defaultvalues;
go 4select*from dbo.TestTranTable1;ifexists(select1from sys.sql_modules where object_id = object_id('dbo.ChangeValues'))begindropproc dbo.ChangeValues;end
go
createproc dbo.ChangeValues
asupdate dbo.TestTranTable1
set some_int =11where id =1;update dbo.TestTranTable1
set some_int =12where id =2;update dbo.TestTranTable1
set some_int =13where id =3;-- this will error out (arithmetic overflow)update dbo.TestTranTable1
set some_int =2147483648where id =4;
go
exec dbo.ChangeValues;select*from dbo.TestTranTable1;
Oto wynik:
Tworząc sesję zdarzeń rozszerzonych w celu monitorowania sql_transactionzdarzenia, oto wynik działaniadbo.ChangeValues :
Jak widać na powyższym zrzucie ekranu, dla każdego z czterech wyciągów są osobne transakcje. Pierwsze 3 zatwierdzenie, a ostatnie wycofuje się z powodu błędu.
Myślę, że może tu być pewne zamieszanie dotyczące partii w porównaniu do transakcji .
Transakcja jest oświadczenie lub zestaw instrukcji, które będą albo uda lub nie jako jednostki. Wszystkie instrukcje DDL są w samych transakcjach (tzn. Jeśli zaktualizujesz 100 wierszy, ale wiersz 98 zgłasza błąd, żaden z wierszy nie zostanie zaktualizowany). Możesz zawinąć szereg wyciągów w transakcję, używając, BEGIN TRANSACTIONa następnie alboCOMMIT albo ROLLBACK.
partii jest szereg stwierdzeń, które są wykonywane razem. Procedura składowana jest przykładem partii. W procedurze składowanej, jeśli jedna instrukcja zawiedzie i wystąpi pułapka błędu (zwykle TRY/CATCHblokuje), kolejne instrukcje nie zostaną wykonane.
Podejrzewam, że twój problem polega na tym, że partia jest anulowana, gdy wystąpi błąd, ponieważ albo w przechowywanym proc, albo w zewnętrznym zakresie (takim jak aplikacja lub przechowywany proc, który wywołuje tę procedurę) występuje pułapka błędu. W takim przypadku trudniej jest to rozwiązać, ponieważ musisz dostosować sposób obsługi błędów w dowolnym zakresie, w którym są one zatrzymywane.
Nie znalazłem żadnego artykułu, który mówi: „Procedura sklepu jest przykładem partii”. Uważam, że procedura składowana jest bardzo podobna do partii, ale nie jest partią. Główna różnica polega na tym, że SP gwarantuje, że zostanie skompilowana z wyprzedzeniem i będzie gotowa do wykonania wiele razy, w przeciwieństwie do partii. Podobieństwa są następujące: - Oba wykonują każde polecenie na raz. - Jeśli jedno polecenie nie powiedzie się, zostaną zatwierdzone wszystkie poprzednie polecenia (chyba że działało w transakcji) - Jeśli jedno polecenie nie powiodło się, wszystkie następne polecenia nie zostaną wykonane.
Ashi,
6
Wszystko na serwerze SQL jest zawarte w transakcji.
Gdy wyraźnie to określisz, begin transactiona end transactionnastępnie nazywa się to Transakcja jawna . Jeśli nie, to jest to transakcja niejawna .
Aby zmienić tryb, w którym się znajdujesz, możesz użyć
set implicit_transactions on
lub
set implicit_transactions offselect@@OPTIONS &2
jeśli powyżej zwraca 2, jesteś w trybie transakcji niejawnych. Jeśli zwróci 0, jesteś w automatycznym zatwierdzaniu.
Transakcja jest WSZYSTKO lub nic, aby utrzymać bazę danych w spójnym stanie. Pamiętaj właściwości ACID.
W ten sposób domyślnie działają procedury składowane. Procedura przechowywana nie jest automatycznie pakowana w transakcję.
Jeśli chcesz, aby procedura przechowywana zatrzymała się, gdy wystąpi pierwszy błąd, umieść tam login TRY / CATCH, aby powrócić w przypadku na przykład problemu z poleceniem 2.
Chcę zakwalifikować te pojedyncze transakcje jako zachowanie domyślne dla procedur przechowywanych, ponieważ wszystkie instrukcje są opakowane w transakcje niejawne; jednak nikt nie powinien polegać na niejawnych transakcjach w celu kontrolowania przeznaczenia swojego kodu. O wiele lepszą praktyką jest jawne kontrolowanie sposobu obsługi transakcji w kodzie produkcyjnym.
oddziel każdą część BEGIN TRAN i sprawdź, czy transakcja się powiodła. jeśli zostało to zatwierdzone, w przeciwnym razie wykonaj wycofanie, ponieważ wszystkie wykonują z tego samego poziomu, będziesz mógł zatwierdzić każdą sekcję osobno, bez konieczności cofania wszystkich, jeśli jedna zawiedzie.
Czy spowoduje to utworzenie transakcji podrzędnych w ramach mojej procedury składowanej? Idealnie chciałbym tego uniknąć, jeśli to możliwe
Matthew Steeples,
1
Jeśli SP jest wywoływany z transakcji, odpowiedzią są zapisane powyżej transakcje. Jeśli sp nie jest wywoływane za pomocą, to @mrdenny jest poprawny. Serwer SQL nie obsługuje zagnieżdżonej transakcji.
Żeby było jasne (i dla leniwych, którzy nie chcą klikać linków), tak naprawdę nie rozpoczynasz kolejnej transakcji. Aka tytuł na stanowisku Paula: „Mit: Zagnieżdżone transakcje są prawdziwe”. To nie są prawdziwe transakcje. COMMIT w transakcji zagnieżdżonej nie robi nic oprócz zmniejszenia @@ TRANCOUNT. To prawda, że nie pojawia się błąd, jeśli zagnieżdżasz BEGIN TRAN / COMMIT, ale różni się to od posiadania prawdziwych zagnieżdżonych tranzycji.
Wszystko na serwerze SQL jest zawarte w transakcji.
Gdy wyraźnie to określisz,
begin transaction
aend transaction
następnie nazywa się to Transakcja jawna . Jeśli nie, to jest to transakcja niejawna .Aby zmienić tryb, w którym się znajdujesz, możesz użyć
lub
jeśli powyżej zwraca 2, jesteś w trybie transakcji niejawnych. Jeśli zwróci 0, jesteś w automatycznym zatwierdzaniu.
Transakcja jest WSZYSTKO lub nic, aby utrzymać bazę danych w spójnym stanie. Pamiętaj właściwości ACID.
- utwórz teraz SP - zwróć uwagę, że pierwsze 3 odniosą sukces, a czwarte nie powiedzie się z powodu obcięcia łańcucha ...
Zobacz: Czy zawsze jest to zła praktyka?
źródło
W ten sposób domyślnie działają procedury składowane. Procedura przechowywana nie jest automatycznie pakowana w transakcję.
Jeśli chcesz, aby procedura przechowywana zatrzymała się, gdy wystąpi pierwszy błąd, umieść tam login TRY / CATCH, aby powrócić w przypadku na przykład problemu z poleceniem 2.
źródło
Będziesz potrzebował indywidualnych transakcji dla każdego polecenia. Możesz to również zrobić za pomocą zapisanych transakcji:
Widzieć
SAVE TRANSACTION (Transact-SQL)
w dokumentacji produktu.Chcę zakwalifikować te pojedyncze transakcje jako zachowanie domyślne dla procedur przechowywanych, ponieważ wszystkie instrukcje są opakowane w transakcje niejawne; jednak nikt nie powinien polegać na niejawnych transakcjach w celu kontrolowania przeznaczenia swojego kodu. O wiele lepszą praktyką jest jawne kontrolowanie sposobu obsługi transakcji w kodzie produkcyjnym.
źródło
oddziel każdą część BEGIN TRAN i sprawdź, czy transakcja się powiodła. jeśli zostało to zatwierdzone, w przeciwnym razie wykonaj wycofanie, ponieważ wszystkie wykonują z tego samego poziomu, będziesz mógł zatwierdzić każdą sekcję osobno, bez konieczności cofania wszystkich, jeśli jedna zawiedzie.
Więcej informacji można znaleźć na stronie: http://msdn.microsoft.com/en-us/library/ms188929.aspx
źródło