Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Korzystanie z transakcji ROLLBACK w SQL Server

Wprowadzenie

Całkiem niedawno mój kolega przyszedł do mnie w desperacji, przyznając, że wydał oświadczenie aktualizujące bez klauzuli WHERE w tabeli kluczowych aplikacji. Konsekwencje dla frontendu byłyby tragiczne, więc zwrócił się do mnie bezpośrednio, ponieważ pilnie potrzebował pomocy w odwróceniu sytuacji w jakikolwiek sposób, zanim e-maile i eskalacja zaczną napływać.

Kiedy przyjrzeliśmy się sytuacji, stwierdziliśmy, że zmiany nie zostały zastosowane w dodatkowej bazie danych. W większości przypadków opóźnienie między naszą podstawową i dodatkową bazą danych wynosi dwadzieścia minut (mamy trochę oszałamiające, aby uniknąć problemów z wydajnością). Ponieważ kolega poprosił o pomoc natychmiast po zorientowaniu się w błędzie, udało nam się odzyskać dane z wtórnej bazy danych. Wartość takiego opóźnienia opisałem w tym artykule .

Przegląd scenariusza

Scenariusz, który opisałem powyżej, nie jest niczym niezwykłym. Jednym z powodów, dla których zdarza się to zwykłym użytkownikom SQL Server, jest to, że SQL Server używa tak zwanych niejawnych transakcji. Transakcje niejawne są domyślnie wyłączone, co oznacza, że ​​program SQL Server nie oczekuje wydania instrukcji COMMIT TRANSACTION na końcu każdej instrukcji. W efekcie każda instrukcja jest zatwierdzana automatycznie. Jest to wygodne i pomaga uniknąć sytuacji, w których sesje, które nie zostały jeszcze zatwierdzone, blokują zasoby i wpływają na wydajność. Brent Ozar zawiera więcej szczegółów na temat wpływu na wydajność transakcji IMPLICIT =ON.

Jednak małą wadą tej konfiguracji (IMPLICIT TRANSACTIONS =OFF) jest to, że użytkownicy nie mają możliwości ponownego przemyślenia wypowiedzi i wydania ROLLBACK, co jest bardzo powszechne w Oracle. Rys. 1 przedstawia opcje zapytań ANSI dostępne w SQL Server Management Studio.

Rys. 1 Domyślne ustawienia ANSI w SQL Server Management Studio

Korzystanie z transakcji niejawnych

W istocie problem, z jakim mamy do czynienia w tej domyślnej konfiguracji lub naszym najbardziej pożądanym narzędziu klienta, polega na tym, że nie możemy ROLLBACK po wykonaniu instrukcji SQL. Możemy to obejść, włączając TRANSAKCJE IMPLICIT w naszej sesji. Da nam to możliwość ROLLBACK transakcji, jeśli zajdzie taka potrzeba. Rys. 2 i Rys. 4 pokazują nam, że możemy włączyć to ustawienie tylko dla jednej sesji, nawet jeśli nie eliminuje to ryzyka zablokowania sesji użytkownika przez innych, jeśli nie zostanie wydane ROLLBACK lub COMMIT.

Rys. 2 NIEjawne transakcje w jednej sesji

-- Listing 1: UPDATE Table TAB2 with IMPLICIT_TRANSACTIONS ON
SET IMPLICIT_TRANSACTIONS ON

DECLARE @IMPLICIT_TRANSACTIONS VARCHAR(3) = 'OFF';  
IF ( (2 & @@OPTIONS) = 2 ) SET @IMPLICIT_TRANSACTIONS = 'ON';  
SELECT @IMPLICIT_TRANSACTIONS AS IMPLICIT_TRANSACTIONS;

USE KTrain
GO
SELECT * FROM Tab2;
GO

UPDATE TAB2
SET countryCode='SA'
-- WHERE fname='Joyce';
GO
SELECT * FROM Tab2;
GO

Rys. Zaktualizowano 3 wszystkie wiersze

Aby zilustrować opisane tutaj obejście, spójrzmy na kod SQL z Listingu 1. Załóżmy, że zwykły użytkownik SQL Server, młodszy programista, otrzymał zestaw skryptów do wykonania w określonych warunkach . W skrypcie klauzula WHERE została wykomentowana, ponieważ oczekuje się, że za każdym razem, gdy wykonują ten skrypt, powinni zmienić predykat. Oczywiście jest to prosty przypadek użycia, a ryzyko można rozwiązać na wiele sposobów, ale chcemy tylko pokazać możliwość wykonania ROLLBACK.

Przypomnijmy, że włączyliśmy już IMPLICIT TRANSACTION, więc kiedy wykonamy tę instrukcję, SQL Server będzie oczekiwał od nas albo COMMIT, albo ROLLBACK transakcji. Intencją dewelopera jest aktualizacja kodu countryCode Joyce Afam do „SA”, ponieważ wyemigrowała do RPA. Rys. 3 pokazuje nam, że deweloper próbując to zrobić, przypadkowo zaktualizował wszystkie wiersze wartością SA jako countryCode . Zauważają to i wydają COFNIĘCIE.

Rys. 4 Wydanie ROLLBACK

Rys. 5 NIEjawnych transakcji w kolejnej sesji

Jednak w drugiej sesji, w której nie włączyliśmy IMPLICIT TRANSACTIONS, okazuje się, że programista nie jest w stanie naprawić błędu. W tym przypadku nie mogą pomyślnie wydać ROLLBACK. Odzyskiwanie wiązałoby się wówczas z przywróceniem danych.

Rys. 6 COFNIĘCIE nie jest możliwe bez NIEjawnych TRANSAKCJI WŁĄCZONE

Korzystanie z jawnych transakcji

Innym podejściem do osiągnięcia tego samego efektu jest uwzględnienie DML w transakcji poprzez jawne stwierdzenie BEGIN TRAN. Ponownie, bardzo ważne jest, aby zakończyć transakcję – używając opcji COMMIT lub ROLLBACK. W kontekście tej dyskusji wydajemy ROLLBACK, ponieważ zdajemy sobie sprawę, że w kodzie jest błąd.

-- Listing 2: UPDATE Table TAB2 with Explicit Transaction

BEGIN TRAN 
GO
USE KTrain
GO
SELECT * FROM Tab2;
GO

UPDATE TAB2
SET countryCode='GH'
-- WHERE fname='Joyce';
GO
SELECT * FROM Tab2;
GO

ROLLBACK;

SELECT * FROM Tab2;
GO

- Listing 3: Corrected UPDATE Statement

BEGIN TRAN 
GO
USE KTrain
GO
SELECT * FROM Tab2;
GO

UPDATE TAB2
SET countryCode='SA'
WHERE fname='Joyce';
GO
SELECT * FROM Tab2;
GO

Wniosek

W tym artykule omówiliśmy pokrótce dobre obejście umożliwiające tworzenie możliwości ROLLBACK, a tym samym łagodzenie błędów użytkownika wynikających z niewłaściwego DML. Zwróciliśmy również uwagę na kluczowe ryzyko tego podejścia, którym jest nieumyślne blokowanie. Administrator danych może rozpocząć dochodzenie w sprawie możliwej obecności tego zagrożenia, wysyłając zapytanie do sys.dm_tran_session_transactions, sys.dm_tran_locks i podobne obiekty dynamicznego zarządzania.

Odniesienia

  1. Naprawianie utraty danych za pomocą przesyłania dzienników z opóźnionym odzyskiwaniem

  2. Ustaw transakcje niejawne

  3. Ustaw transakcje niejawne jako zły pomysł

  4. DMV dla transakcji


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak uruchomić SQL Server 2017 i 2019 jednocześnie na komputerze Mac?

  2. Zaktualizuj SQL z numeracją porządkową

  3. Dzielenie ciągu w serwerze sql

  4. Jak zmapować pole encji, którego nazwa jest słowem zastrzeżonym w JPA?

  5. SQL Server:Czy można wstawiać do dwóch tabel jednocześnie?