sql >> Database >  >> RDS >> Sqlserver

Fout- en transactieafhandeling implementeren in SQL Server

Inleiding

Hoe hard we ook proberen om applicaties te ontwerpen en te ontwikkelen, fouten zullen altijd voorkomen. Er zijn twee algemene categorieën:syntaxis- of logische fouten kunnen zowel programmatische fouten zijn als gevolgen van een onjuist databaseontwerp. Anders kunt u een foutmelding krijgen vanwege de verkeerde gebruikersinvoer.

Met T-SQL (de programmeertaal voor SQL Server) kunnen beide fouttypen worden afgehandeld. U kunt fouten in de toepassing opsporen en beslissen wat u moet doen om fouten in de toekomst te voorkomen.

De meeste toepassingen vereisen dat u fouten registreert, gebruiksvriendelijke foutrapportage implementeert en, indien mogelijk, fouten afhandelt en de uitvoering van de toepassing voortzet.

Gebruikers behandelen fouten op instructieniveau. Het betekent dat wanneer u een batch SQL-opdrachten uitvoert en het probleem zich voordoet in de laatste instructie, alles dat aan dat probleem voorafgaat, als impliciete transacties in de database wordt vastgelegd. Dit is misschien niet wat je wenst.

Relationele databases zijn geoptimaliseerd voor het uitvoeren van batchstatements. U moet dus een reeks instructies als één eenheid uitvoeren en alle instructies niet halen als één instructie mislukt. U kunt dit bereiken door transacties te gebruiken. Dit artikel richt zich op zowel foutafhandeling als transacties, aangezien deze onderwerpen sterk met elkaar verbonden zijn.

SQL-foutafhandeling

Om uitzonderingen te simuleren, moeten we ze op een herhaalbare manier produceren. Laten we beginnen met het eenvoudigste voorbeeld – delen door nul:

SELECT 1/0

De uitvoer beschrijft de gegenereerde fout - Delen door nul opgetreden fout . Maar deze fout is niet behandeld, geregistreerd of aangepast om een ​​gebruiksvriendelijk bericht te produceren.

Het afhandelen van uitzonderingen begint met het plaatsen van instructies die u wilt uitvoeren in het BEGIN TRY…END TRY-blok.

SQL Server verwerkt (vangt) fouten in het BEGIN CATCH…END CATCH-blok, waar u aangepaste logica kunt invoeren voor foutregistratie of -verwerking.

Het BEGIN CATCH-statement moet direct na het END TRY-statement volgen. De uitvoering wordt dan doorgegeven van het TRY-blok naar het CATCH-blok bij de eerste fout die zich voordoet.

Hier kunt u beslissen hoe u met de fouten omgaat, of u de gegevens over gemelde uitzonderingen wilt loggen of een gebruiksvriendelijk bericht wilt maken.

SQL Server heeft ingebouwde functies die u kunnen helpen bij het extraheren van foutdetails:

  • ERROR_NUMBER():Geeft het aantal SQL-fouten terug.
  • ERROR_SEVERITY():Geeft het ernstniveau terug dat het type probleem aangeeft en het niveau ervan. Niveaus 11 tot 16 kunnen door de gebruiker worden afgehandeld.
  • ERROR_STATE():Retourneert het foutstatusnummer en geeft meer details over de gegenereerde uitzondering. U gebruikt het foutnummer om in de Microsoft Knowledge Base te zoeken naar specifieke foutdetails.
  • ERROR_PROCEDURE():Retourneert de naam van de procedure of trigger waarin de fout is opgetreden, of NULL als de fout niet is opgetreden in de procedure of trigger.
  • ERROR_LINE():Retourneert het regelnummer waarop de fout is opgetreden. Dit kan het regelnummer zijn van procedures of triggers of het regelnummer in de batch.
  • ERROR_MESSAGE():Retourneert de tekst van het foutbericht.

Het volgende voorbeeld laat zien hoe u met fouten omgaat. Het eerste voorbeeld bevat de Delen door nul fout, terwijl de tweede verklaring juist is.

BEGIN TRY
   PRINT 1/0  
   SELECT 'Correct text'
END TRY
BEGIN CATCH
   SELECT ERROR_NUMBER() AS ERR_NO
   ,      ERROR_SEVERITY() AS ERR_SEV
   ,      ERROR_STATE() AS ERR_STATE
   ,      ERROR_LINE() AS ERR_LINE
   ,      ERROR_MESSAGE() AS ERR_MESSAGE
END CATCH

Als de tweede instructie wordt uitgevoerd zonder foutafhandeling (SELECT 'Correct text'), zou het lukken.

Aangezien we de aangepaste foutafhandeling in het TRY-CATCH-blok implementeren, wordt de uitvoering van het programma doorgegeven aan het CATCH-blok na de fout in de eerste instructie, en de tweede instructie is nooit uitgevoerd.

Op deze manier kunt u de tekst die aan de gebruiker wordt gegeven aanpassen en beter controleren wat er gebeurt als een fout plaatsvindt. We loggen bijvoorbeeld fouten in een logtabel voor verdere analyse.

Transacties gebruiken

De bedrijfslogica kan bepalen dat het invoegen van de eerste instructie mislukt wanneer de tweede instructie mislukt, of dat u wijzigingen van de eerste instructie moet herhalen bij het mislukken van de tweede instructie. Door transacties te gebruiken, kunt u een reeks overzichten als één eenheid uitvoeren die ofwel faalt of slaagt.

Het volgende voorbeeld laat het gebruik van transacties zien.

Eerst maken we een tabel om de opgeslagen gegevens te testen. Vervolgens gebruiken we twee transacties in het TRY-CATCH-blok om te simuleren wat er gebeurt als een deel van de transactie mislukt.

We zullen de CATCH-instructie gebruiken met de XACT_STATE()-instructie. De functie XACT_STATE() wordt gebruikt om te controleren of de transactie nog bestaat. In het geval dat de transactie automatisch wordt teruggedraaid, zou de ROLLBACK TRANSACTIE een nieuwe uitzondering opleveren.

Maak een buit met de onderstaande code:

-- CREATE TABLE TEST_TRAN(VALS INT)

BEGIN TRY
   BEGIN TRANSACTION
       INSERT INTO TEST_TRAN(VALS) VALUES(1);
   COMMIT TRANSACTION  

   BEGIN TRANSACTION
       INSERT INTO TEST_TRAN(VALS) VALUES(2);
       INSERT INTO TEST_TRAN(VALS) VALUES('A'); 
       INSERT INTO TEST_TRAN(VALS) VALUES(3);
   COMMIT TRANSACTION
END TRY
BEGIN CATCH  
   IF XACT_STATE() > 0 ROLLBACK TRANSACTION

   SELECT ERROR_NUMBER() AS ERR_NO
   ,      ERROR_SEVERITY() AS ERR_SEV
   ,      ERROR_STATE() AS ERR_STATE
   ,      ERROR_LINE() AS ERR_LINE
   ,      ERROR_MESSAGE() AS ERR_MESSAGE

END CATCH

SELECT * FROM TEST_TRAN

-- DROP TABLE TEST_TRAN

De afbeelding toont de waarden in de TEST_TRAN-tabel en foutmeldingen:

Zoals u ziet, is alleen de eerste waarde vastgelegd. Bij de tweede transactie hadden we een typeconversiefout in de tweede rij. Dus de hele batch teruggedraaid.

Op deze manier kunt u bepalen welke gegevens de database binnenkomen en hoe batches worden verwerkt.

Aangepast foutbericht genereren in SQL

Soms willen we aangepaste foutmeldingen maken. Meestal zijn ze bedoeld voor scenario's waarin we weten dat er een probleem kan optreden. We kunnen onze eigen aangepaste berichten produceren die zeggen dat er iets mis is, zonder technische details te tonen. Daarvoor gebruiken we het THROW-trefwoord.

BEGIN TRY
   IF ( SELECT COUNT(sys.all_objects) > 1 )
	THROW ‘More than one object is ALL_OBJECTS system table’
END TRY
BEGIN CATCH
   SELECT ERROR_NUMBER() AS ERR_NO
   ,      ERROR_SEVERITY() AS ERR_SEV
   ,      ERROR_STATE() AS ERR_STATE
   ,      ERROR_LINE() AS ERR_LINE
   ,      ERROR_MESSAGE() AS ERR_MESSAGE
END CATCH

Of we willen graag een catalogus met aangepaste foutmeldingen voor categorisering en consistentie van foutbewaking en -rapportage. Met SQL Server kunnen we de code, de ernst en de status van het foutbericht vooraf definiëren.

Een opgeslagen procedure genaamd "sys.sp_addmessage" wordt gebruikt om aangepaste foutmeldingen toe te voegen. We kunnen het gebruiken om de foutmelding op meerdere plaatsen op te roepen.

We kunnen RAISERROR aanroepen en het berichtnummer als parameter verzenden in plaats van dezelfde foutdetails op meerdere plaatsen in de code hard te coderen.

Door de onderstaande geselecteerde code uit te voeren, voegen we de aangepaste fout toe aan SQL Server, verhogen deze en gebruiken vervolgens sys.sp_dropmessage om het gespecificeerde door de gebruiker gedefinieerde foutbericht te verwijderen:

exec sys.sp_addmessage @msgnum=55000, @severity = 11, 
                                          @msgtext = 'My custom error message'
GO

RAISERROR(55000,11,1)
GO

exec sys.sp_dropmessage @msgnum=55000
GO

We kunnen ook alle berichten in SQL Server bekijken door het onderstaande queryformulier uit te voeren. Onze aangepaste foutmelding is zichtbaar als het eerste item in de resultatenset:

SELECT * FROM master.dbo.sysmessages

Maak een systeem om fouten te loggen

Het is altijd handig om fouten te loggen voor latere foutopsporing en verwerking. Je kunt ook triggers op deze gelogde tabellen zetten en zelfs een e-mailaccount instellen en een beetje creatief zijn in het waarschuwen van mensen wanneer er een fout optreedt.

Om fouten te loggen, maken we een tabel met de naam DBError_Log , die kan worden gebruikt om de logdetailgegevens op te slaan:

CREATE TABLE DBError_Log
(
    DBError_Log_ID    INT IDENTITY(1, 1) PRIMARY KEY,
    UserName              VARCHAR(100),
    ErrorNumber    INT,
    ErrorState     INT,
    ErrorSeverity  INT,
    ErrorLine      INT,
    ErrorProcedure VARCHAR(MAX),
    ErrorMessage   VARCHAR(MAX),
    ErrorDateTime  DATETIME
);

Om het logmechanisme te simuleren, maken we de GenError opgeslagen procedure die de Delen door nul . genereert fout en registreert de fout in de DBError_Log tafel:

CREATE PROCEDURE dbo.GenError
AS
  BEGIN TRY
    SELECT 1/0
  END TRY
  BEGIN CATCH
    INSERT INTO dbo.DBError_Log
    VALUES
    (SUSER_SNAME(),
     ERROR_NUMBER(),
     ERROR_STATE(),
     ERROR_SEVERITY(),
     ERROR_LINE(),
     ERROR_PROCEDURE(),
     ERROR_MESSAGE(),
     GETDATE()
	);
  END CATCH
GO

EXEC dbo.GenError
SELECT * FROM  dbo.DBError_Log

De DBError_Log tabel bevat alle informatie die we nodig hebben om de fout te debuggen. Het biedt ook aanvullende informatie over de procedure die de fout heeft veroorzaakt. Hoewel dit misschien een triviaal voorbeeld lijkt, kunt u deze tabel uitbreiden met extra velden of deze gebruiken om hem te vullen met op maat gemaakte uitzonderingen.

Conclusie

Als we applicaties willen onderhouden en debuggen, willen we in ieder geval melden dat er iets mis is gegaan en dat ook onder de motorkap loggen. Wanneer we een applicatie op productieniveau hebben die door miljoenen gebruikers wordt gebruikt, is een consistente en rapporteerbare foutafhandeling de sleutel tot het debuggen van problemen tijdens runtime.

Hoewel we de oorspronkelijke fout in het databasefoutenlogboek konden vastleggen, zouden gebruikers een vriendelijker bericht moeten zien. Het zou dus een goed idee zijn om aangepaste foutmeldingen te implementeren die naar aanroepende applicaties worden gestuurd.

Welk ontwerp u ook implementeert, u moet gebruikers- en systeemuitzonderingen registreren en afhandelen. Deze taak is niet moeilijk met SQL Server, maar u moet deze vanaf het begin plannen.

Het toevoegen van foutafhandelingsbewerkingen aan databases die al in productie zijn, kan ernstige code-refactoring en moeilijk te vinden prestatieproblemen met zich meebrengen.


  1. Microsoft Access optimaliseren met SQL Server IndyPass – 21-5-19

  2. Hoe TRIM() werkt in MariaDB

  3. Een overzicht van Quests Nieuwste databasebewakingsservice - Spotlight Cloud

  4. LIMIT trefwoord op MySQL met voorbereide verklaring