För det första, låsning av en tabell kommer inte att hindra en annan session från att utfärda SELECT
uttalanden mot uppgifterna.
I session 1, om jag låser bordet
SQL> lock table foo in exclusive mode;
Table(s) Locked.
Jag kan sedan starta Session 2 och fråga efter data allt jag vill
SQL> select * from foo;
COL1
----------
1
1
I Oracle blockerar inte skribenter läsare så du kan aldrig förhindra en annan session från att fråga efter data i en tabell.
Det låter som att det du försöker implementera är pessimistisk låsning. I så fall, istället för att låsa tabellen, gör du en SELECT FOR UPDATE
som låser den särskilda posten du tänker bearbeta. Så länge alla andra sessioner också försöker göra en SELECT FOR UPDATE
(beroende på Oracle-versionen, eventuellt lägga till SKIP LOCKED
qualifier och/eller WAIT
kval). Det låser den specifika raden du bearbetar och låter den andra sessionen antingen välja en annan rad eller timeout eller upptäcka att det inte finns några rader att bearbeta beroende på detaljerna för implementeringen. Det innebär inte att du låser bordet.
Det enda sättet för ett lås att frigöras är att sessionen som skaffade det släpper det (i allmänhet genom att avsluta transaktionen) eller att sessionen som skaffade det avslutas. Om klientapplikationen fortfarande körs men inte gör något för att frigöra låset eller avsluta sessionen kommer låset att hållas på obestämd tid. En DBA skulle behöva explicit döda sessionen, låta transaktionen rulla tillbaka och släppa låset för att få systemet igång igen. Om klientapplikationen slutar att köras eller åtminstone slutar svara (jag är fortfarande inte klar över exakt vilket felscenario du diskuterar), är det möjligt att aktivera upptäckt av döda anslutningar (DCD) via 'SQLNET.EXPIRE_TIME'-parameter på databasnivå skulle få databasen att fastställa att klienten inte svarar och att automatiskt döda sessionen, rulla tillbaka transaktionen och släppa låset.
Om det finns flera sessioner som bearbetar data är det i allmänhet mycket att föredra att använda någon form av optimistisk låsning. Annars designar du ett system som oundvikligen kommer att behöva DBA för att snabbt hitta och döda sessioner för att få affärsanvändarna att arbeta igen och som kommer att kräva mer och mer ingripande ju mer det blir. Det är inget som DBA:er tycker om att göra och inte något affärsanvändare tycker om att klaga på. Ett enkelt optimistiskt låssystem skulle så något liknande
- Välj en nyckel att bearbeta och något slags datum som anger när raden senast uppdaterades.
- Uppdatera en statuskolumn till "bearbetar" så att andra sessioner inte försöker bearbeta samma rad.
- Bearbeta posten i din ansökan
- När du är klar med bearbetningen uppdaterar du informationen med nyckeln och tiden du valde i det första steget. Om du uppdaterar 1 rad vet du att ingen annan session har ändrat den aktuella informationen sedan du valde den. Om du uppdaterar 0 rader vet du att någon annan session har ändrat data sedan du valde den.
Med den här typen av arkitektur är det relativt enkelt att fråga databasen för att se vilka rader som bearbetas och att till exempel ha ett jobb som återställer statuskolumnen till "obearbetad" efter en viss tid om klienten inte har gjort det. färdiga. Det är väldigt enkelt för andra sessioner att välja en annan rad att bearbeta. Och det är relativt säkert om till exempel applikationen fryser i ett par timmar och sedan återhämtar sig eftersom den bara upptäcker när den är klar att bearbetningen att någon annan session redan har bearbetat raden igen.