sql >> Databasteknik >  >> RDS >> Sqlserver

Använda Transaktion ROLLBACK i SQL Server

Introduktion

Mycket nyligen kom en kollega till mig i desperation och ägde att han hade utfärdat ett uppdateringsutlåtande utan en WHERE-klausul i en nyckelprogramtabell. Implikationerna på fronten skulle vara fruktansvärda, så han kom till mig direkt eftersom han akut behövde hjälp med att vända situationen på något sätt innan e-postmeddelanden och eskaleringen började strömma in.

När vi undersökte situationen fann vi att ändringarna inte har tillämpats i den sekundära databasen. I de flesta fall är fördröjningen mellan våra primära och sekundära databaser tjugo minuter (vi har lite häpnadsväckande för att undvika prestandaproblem). Eftersom min kollega bad om hjälp direkt efter att ha upptäckt felet kunde vi återställa data från den sekundära databasen. Jag beskrev värdet av en sådan försening i den här artikeln .

Scenariogranskning

Scenariot jag beskrev ovan är inte ovanligt. En av anledningarna till att detta händer vanliga SQL Server-användare är att SQL Server använder det som kallas implicita transaktioner. Implicita transaktioner är avstängda som standard, vilket innebär att SQL Server inte förväntar sig att du utfärdar en COMMIT TRANSACTION-sats i slutet av varje sats. I själva verket begås varje uttalande automatiskt. Det här är bekvämt och hjälper till att undvika situationer där sessioner som ännu inte har genomförts slutar låsa resurser och påverka prestandan. Brent Ozar ger mer information om prestandakonsekvenserna av IMPLICIT TRANSACTIONS =ON.

En liten nackdel med den här konfigurationen (IMPLICIT TRANSACTIONS =OFF) är dock att användare inte har möjlighet att tänka om ett uttalande och göra en ROLLBACK, vilket är mycket vanligt i Oracle. Fig. 1 visar ANSI-frågealternativen som är tillgängliga i SQL Server Management Studio.

Fig. 1 ANSI-standardinställningar i SQL Server Management Studio

Använda implicita transaktioner

I huvudsak är problemet vi står inför i den här standardkonfigurationen eller vårt mest önskvärda klientverktyg att vi inte kan ROLLBACK när vi väl har kört en SQL-sats. Vi kan kringgå detta genom att aktivera IMPLICITTA TRANSAKTIONER i vår session. Detta kommer att ge oss möjligheten att ROLLBACK transaktioner om vi behöver. Fig. 2 och Fig. 4 visar oss att vi kan ha den här inställningen aktiverad endast för en session, även om detta inte tar bort risken för att användarsessionen blockerar andra om en ROLLBACK eller COMMIT inte utfärdas.

Fig. 2 IMPLICITTA TRANSAKTIONER PÅ i en session

-- 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

Fig. 3 Alla rader uppdaterade

För att illustrera lösningen som beskrivs här, låt oss titta på SQL-koden i Lista 1. Låt oss anta att en vanlig SQL Server-användare, en junior utvecklare, har fått en uppsättning skript att köra under vissa förhållanden . I skriptet har WHERE-satsen kommenterats bort eftersom det förväntas att varje gång de kör detta skript ska de ändra predikatet. Naturligtvis är detta ett enkelt användningsfall och risken kan hanteras på ett antal sätt, men vi vill bara visa möjligheten att utföra en ROLLBACK.

Kom ihåg att vi redan har aktiverat IMPLICIT TRANSACTION, så när vi kör den här satsen kommer SQL Server att förvänta sig att vi antingen COMMIT eller ROLLBACK transaktionen. Utvecklarens avsikt är att uppdatera Joyce Afams landskod till 'SA' sedan hon har immigrerat till Sydafrika. Fig. 3 visar att utvecklaren, medan han försökte göra detta, av misstag har uppdaterat alla rader med värdet SA som countryCode . De märker detta och gör en ROLLBACK.

Fig. 4 Utfärda ROLLBACK

Fig. 5 IMPLICITTA TRANSAKTIONER PÅ i en annan session

Men i den andra sessionen där vi inte har aktiverat IMPLICIT TRANSACTIONS, finner vi att utvecklaren inte kan återhämta sig från sitt fel. De kan inte göra en ROLLBACK i detta fall. Återställning skulle då medföra dataåterställning.

Fig. 6 ÅTERSTÄLLNING inte möjlig utan IMPLICITTA TRANSAKTIONER PÅ

Använda explicita transaktioner

En annan metod för att uppnå samma effekt är att inkludera DML i en transaktion genom att uttryckligen ange BEGIN TRAN. Återigen är det mycket viktigt att slutföra transaktionen – genom att använda antingen COMMIT eller ROLLBACK. I samband med denna diskussion gör vi en ROLLBACK eftersom vi inser att det finns ett fel i koden.

-- 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

Slutsats

I den här artikeln har vi kort berört en bra lösning för att skapa möjligheter för ROLLBACK och på så sätt mildra användarfel till följd av felaktig DML. Vi har också lyft fram en nyckelrisk med detta tillvägagångssätt, som är oavsiktlig blockering. En DBA kan påbörja undersökningar av den möjliga förekomsten av denna risk genom att fråga sys.dm_tran_session_transactions, sys.dm_tran_locks , och liknande dynamiska hanteringsobjekt.

Referenser

  1. Åtgärda dataförlust med logfrakt med försenad återställning

  2. Ange implicita transaktioner

  3. Ange implicita transaktioner som en dålig idé

  4. DMV för transaktioner


  1. Postgresql - det går inte att släppa databasen på grund av vissa automatiska anslutningar till DB

  2. ExecuteNonQuery:Anslutningsegenskapen har inte initierats.

  3. Genererar djupbaserat träd från hierarkiska data i MySQL (inga CTE)

  4. Hur man använder egenskapen IDENTITY() i SQL Server