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:
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).
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:
Nadelen:
Volledige logica is verpakt in TRY/CATCH, geneste procedures gebruiken SAVEPOINT of opereren binnen één externe transactie, alle fouten worden gelogd.
Voordelen:
Nadelen: