ProgrammatieSQL-ontwikkelaar

Hoe implementeer je betrouwbare foutafhandeling (Exception Handling) en transactieomkering in SQL opgeslagen procedures, vooral in het geval van geneste (Nested) transacties? Welke beperkingen en kenmerken hebben dergelijke oplossingen?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

Historisch gezien was foutafhandeling in SQL beperkt tot het terugdraaien van de transactie na een fatale fout. Met de ontwikkeling van bedrijfslogica is het echter steeds vaker vereist om fouten nauwkeurig te loggen, alleen de wijzigingen terug te draaien die zijn aangebracht, en ook de mogelijkheid tot geneste procedure-aanroepen (nested transactions).

Het probleem is dat niet alle DBMS geneste transacties volledig ondersteunen (bijvoorbeeld in MS SQL Server zijn dit eerder niveaus van opgeslagen punten SAVEPOINT, en geen echte transacties), en uitzonderingen bij fouten kunnen de uitvoering onderbreken voordat de nodige opruiming heeft plaatsgevonden, als de mechanismen TRY/CATCH of analogen niet worden gebruikt.

Oplossing: gebruik de constructies TRY/CATCH (of vergelijkbaren), SAVEPOINT voor genesteling en configureer het gedrag van procedures bij fouten (bijvoorbeeld, SET XACT_ABORT in SQL Server).

Voorbeeldcode (MS SQL Server):

BEGIN TRY BEGIN TRANSACTION -- bewerkingen EXEC dbo.InnerProcedure COMMIT TRANSACTION END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION -- log de fout INSERT INTO error_log VALUES (ERROR_NUMBER(), ERROR_MESSAGE(), GETDATE()) END CATCH

Belangrijke kenmerken:

  • Gebruik van TRY/CATCH voor het afhandelen van fouten.
  • Controle van @@TRANCOUNT voor genesteling.
  • SAVEPOINT (of eigen analogen voor handmatige controle van terugkeer naar een punt).

Vragen met een valkuil.

Leidt een fout in een geneste transactie tot een echte omkering van alle wijzigingen?

In de meeste DBMS zijn geneste transacties geen afzonderlijke transacties, maar herstelpunten (SAVEPOINT). Bij een algemene omkering worden alle wijzigingen teruggedraaid tot de initiële (outer) transactie.

Wat gebeurt er als je vergeet @@TRANCOUNT te controleren en een ROLLBACK uitvoert buiten een actieve transactie?

Er zal een fout optreden — er is geen actieve transactie om terug te draaien. Controleer altijd @@TRANCOUNT > 0 voordat je ROLLBACK uitvoert.

Werken triggers en cursors in TRY/CATCH?

Ja, maar fouten in triggers kunnen de overgang naar CATCH veroorzaken en de gehele transactie terugdraaien. Foutafhandeling moet worden voorzien in zowel het lichaam van de procedure als in de aangeroepen objecten (procedures, triggers).

Typische fouten en anti-patronen

  • Gebrek aan controle van @@TRANCOUNT — poging tot omkering van een niet-actieve transactie.
  • Onnodige COMMIT of ROLLBACK in geneste niveaus.
  • Loggen van fouten zonder alle details op te slaan (nummer, tekst, parameters).

Voorbeeld uit het leven

Negatief geval

Verschillende geneste procedures, elke procedure gebruikt BEGIN TRANSACTION / COMMIT zonder TRY/CATCH, bij een fout is een deel van de gegevens veranderd, een deel niet.

Voordelen:

  • Eenvoudige code

Nadelen:

  • Asynchronisatie van de toestand
  • Onverwachte fouten na een storing

Positief geval

Volledige logica is verpakt in TRY/CATCH, geneste procedures gebruiken SAVEPOINT of opereren binnen één externe transactie, alle fouten worden gelogd.

Voordelen:

  • Volledige integriteit
  • Foutauditing

Nadelen:

  • Complexere script
  • Iets moeilijker onderhoud van de autosave-logica.