MainframeSupports
tip uge 26/2007:

Når et SQL-kald eksekveres returnerer det som bekendt en SQLCODE i SQLCA. SQLCODE fortæller noget om, hvordan det gik med at eksekvere SQL-kaldet. Enten blev det udført perfekt (SQLCODE = 0) eller også gik der et eller andet galt (SQLCODE <> 0). Graderne af hvor galt det er gået bestemmer du så selv som programmør, og det altså programmets ansvar at bestemme, hvad der videre skal ske.

Hvis dit SQL-kald giver SQLCODE -911 (deadlock eller timeout) har DB2 dog allerede bestemt noget for dig. DB2 har nemlig foretaget en ROLLBACK. Det er den eneste SQLCODE, der har denne bivirkning, så derfor er det ekstremt vigtigt, at reagere på SQLCODE -911 og det helst ved at sørge for at programmet afsluttes uden at lave yderligere DB2 opdateringer. Hvis en SQLCODE -911 ikke behandles fornuftigt, så vil resultatet med stor sandsynlighed blive inkonsistente data.

Der har i de senere år været en tendens til at opdele applikationer i mindre og mindre bidder. Denne opdeling er en følge af metoder som komponentisering og Service Orienteret Arkitektur (SOA). En af resultaterne af denne opdeling er, at det bliver utroligt svært at gennemskue, hvor er fejl opstår og også at få kommunikeret fejlen op igennem hierarkiet af komponenter. Det kan derfor ske, at en SQLCODE -911 går upåagtet hen.

Hvis du står i en situation, hvor dit program eller system bliver ramt en SQLCODE -911, som ikke bliver opdaget under eksekveringen og derfor ender med at skabe inkonsistente data, så kan du prøve følgende. Lav en SQL INSERT som noget af det første i din unit of work. Lige før du skal udstede en COMMIT, så kontrollerer du, om din INSERT række stadig findes ved at lave en DELETE af rækken. Hvis rækken findes, så er alt fryd og gammen, men hvis den er blevet væk, så er der blevet foretaget en ROLLBACK. Det kan eksempelvis kodes således:

...
SET :myTime = CURRENT TIMESTAMP
INSERT INTO MYROLLBACKCHECKER (MYTIME) VALUES(:myTime)
...
foretag det, der måske giver rollback
...
DELETE FROM MYROLLBACKCHECKER WHERE MYTIME = :myTime
IF SQLCODE = 0
  COMMIT
ELSE
  ROLLBACK
  terminer program
END-IF
...

En vigtig detalje er, at tabellen MYROLLBACKCHECKER skal have et unikt index på myTime, og at DELETE benytter dette index, når rækken skal slettes. Ellers risikerer du at skabe nye SQLCODE -911 problemer (deadlock eller timeout). En elegant detalje ved ovenstående løsning er, at hvis programmet/applikationen er lavet til at kunne restartes, så kan man sætte det til automatisk at restarte, hvis DELETE fejler med SQLCODE 100, for så ved du, at din unit of work er blevet rullet tilbage til sidste COMMIT under alle omstændigheder, selvfølgelig under forudsætning af, at du husker selv at lave ROLLBACK. Tippet finder selvfølgelig ikke ud af, hvor det gik galt, men det sørger for, at der ikke opstår inkonsistente data.

Forrige danske tip        Last tip in english        Tip oversigten