sql >> Database >  >> RDS >> Sqlserver

Transactie ROLLBACK gebruiken in SQL Server

Inleiding

Zeer recentelijk kwam een ​​collega van mij in wanhoop naar me toe, die toegegeven had dat hij een update-instructie had uitgegeven zonder een WHERE-clausule in een sleuteltoepassingstabel. De implicaties aan de voorkant zouden verschrikkelijk zijn, dus hij kwam rechtstreeks naar mij omdat hij dringend hulp nodig had bij het omkeren van de situatie voordat de e-mails en escalatie binnenstroomden.

Toen we de situatie onderzochten, ontdekten we dat de wijzigingen niet zijn toegepast in de secundaire database. In de meeste gevallen is de vertraging tussen onze primaire en secundaire databases twintig minuten (we hebben een beetje vertraging om prestatieproblemen te voorkomen). Doordat mijn collega direct na het constateren van de fout om hulp vroeg, hebben we de gegevens uit de secundaire database kunnen herstellen. Ik heb de waarde van zo'n vertraging beschreven in dit artikel .

Scenariooverzicht

Het scenario dat ik hierboven heb beschreven is niet ongewoon. Een van de redenen waarom dit bij gewone SQL Server-gebruikers gebeurt, is dat SQL Server gebruikmaakt van zogenaamde impliciete transacties. Impliciete transacties zijn standaard UITGESCHAKELD, wat betekent dat SQL Server niet verwacht dat u aan het einde van elke instructie een COMMIT TRANSACTION-instructie geeft. In feite wordt elke verklaring automatisch vastgelegd. Dit is handig en helpt situaties te voorkomen waarin sessies die nog moeten worden vastgelegd, resources blokkeren en de prestaties beïnvloeden. Brent Ozar geeft meer details over de prestatie-implicaties van IMPLICIETE TRANSACTIES =AAN.

Een klein nadeel van deze configuratie (IMPLICIETE TRANSACTIES =UIT) is echter dat gebruikers niet de mogelijkheid hebben om een ​​verklaring te heroverwegen en een ROLLBACK uit te geven, wat heel gebruikelijk is in Oracle. Fig. 1 toont de ANSI-queryopties die beschikbaar zijn in SQL Server Management Studio.

Afb. 1 ANSI-standaarden in SQL Server Management Studio

Impliciete transacties gebruiken

In wezen is het probleem waarmee we worden geconfronteerd in deze standaardconfiguratie of onze meest wenselijke clienttool, dat we niet kunnen ROLLBACK zodra we een SQL-instructie hebben uitgevoerd. We kunnen dit omzeilen door IMPLICIETE TRANSACTIES in onze sessie in te schakelen. Dit geeft ons de mogelijkheid om transacties terug te draaien als dat nodig is. Afb. 2 en Afb. 4 laten zien dat we deze instelling slechts voor één sessie kunnen inschakelen, ook al neemt dit niet het risico weg dat de gebruikerssessie andere blokkeert als er geen ROLLBACK of COMMIT wordt gegeven.

Afb. 2 IMPLICIETE TRANSACTIES AAN in één sessie

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

Afb. 3 alle rijen bijgewerkt

Om de hier beschreven tijdelijke oplossing te illustreren, kijken we naar de SQL-code in Listing 1. Laten we aannemen dat een gewone SQL Server-gebruiker, een junior ontwikkelaar, een set scripts heeft gekregen om onder bepaalde voorwaarden uit te voeren . In het script is de WHERE-component weggelaten omdat verwacht wordt dat elke keer dat ze dit script uitvoeren, ze het predikaat moeten veranderen. Dit is natuurlijk een eenvoudige use-case en het risico kan op een aantal manieren worden aangepakt, maar we willen alleen de mogelijkheid laten zien om een ​​ROLLBACK uit te voeren.

Bedenk dat we IMPLICIETE TRANSACTIE al hebben ingeschakeld, dus wanneer we deze instructie uitvoeren, verwacht SQL Server dat we de transactie COMMIT of ROLLBACK uitvoeren. Het is de bedoeling van de ontwikkelaar om de countryCode . van Joyce Afam bij te werken naar ‘SA’ sinds ze naar Zuid-Afrika is geëmigreerd. Fig. 3 laat ons zien dat de ontwikkelaar, terwijl hij dit probeerde te doen, per ongeluk alle rijen heeft bijgewerkt met de waarde SA als countryCode . Ze merken dit op en geven een ROLLBACK uit.

Afb. 4 ROLLBACK uitgeven

Afb. 5 IMPLICIETE TRANSACTIES AAN in een andere sessie

In de andere sessie waarin we IMPLICIETE TRANSACTIES niet hebben ingeschakeld, stellen we vast dat de ontwikkelaar zijn fout niet kan herstellen. Ze kunnen in dit geval geen ROLLBACK afgeven. Herstel zou dan gegevensherstel met zich meebrengen.

Afb. 6 ROLLBACK niet mogelijk zonder IMPLICIETE TRANSACTIES AAN

Expliciete transacties gebruiken

Een andere benadering om hetzelfde effect te bereiken is om de DML in een transactie in te sluiten door expliciet BEGIN TRAN te vermelden. Nogmaals, het is erg belangrijk om de transactie te voltooien - door COMMIT of ROLLBACK te gebruiken. In de context van deze discussie geven we een ROLLBACK omdat we ons realiseren dat er een fout in de code zit.

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

Conclusie

In dit artikel hebben we het kort gehad over een goede oplossing om mogelijkheden voor ROLLBACK te creëren en zo gebruikersfouten als gevolg van verkeerde DML te verminderen. We hebben ook gewezen op een belangrijk risico van deze aanpak, namelijk onbedoelde blokkering. Een DBA kan een onderzoek starten naar de mogelijke aanwezigheid van dit risico door sys.dm_tran_session_transactions, sys.dm_tran_locks op te vragen. , en soortgelijke dynamische beheerobjecten.

Referenties

  1. Gegevensverlies herstellen met verzending van logbestanden met vertraagd herstel

  2. Impliciete transacties instellen

  3. Stel impliciete transacties in als een slecht idee

  4. DMV's voor transacties


  1. Over het V-formaatelement in Oracle

  2. Wanneer het dringend is?

  3. Oproep naar een lidfunctie execute() op boolean in

  4. ver.2 PyGreSQL ERROR:from _pg import * ImportError:DLL load failed:De opgegeven module kon niet worden gevonden