Innanzitutto, il blocco di una tabella non impedirà a un'altra sessione di emettere SELECT
dichiarazioni contro i dati.
Nella sessione 1, se blocco il tavolo
SQL> lock table foo in exclusive mode;
Table(s) Locked.
Posso quindi avviare la sessione 2 e interrogare tutti i dati che desidero
SQL> select * from foo;
COL1
----------
1
1
In Oracle, i writer non bloccano i lettori, quindi non puoi mai impedire a un'altra sessione di interrogare i dati in una tabella.
Sembra che quello che stai cercando di implementare sia un blocco pessimistico. In tal caso, invece di bloccare la tabella, esegui un SELECT FOR UPDATE
che blocca la voce particolare che intendi elaborare. Finché anche tutte le altre sessioni tentano di eseguire un SELECT FOR UPDATE
(a seconda della versione Oracle, aggiungendo potenzialmente il SKIP LOCKED
qualificatore e/o il WAIT
qualificatore). Ciò blocca la riga specifica che stai elaborando e consente alla seconda sessione di selezionare una riga diversa o di andare in timeout oppure di scoprire che non ci sono righe da elaborare a seconda delle specifiche dell'implementazione. Ciò non comporta il blocco della tabella.
L'unico modo per rilasciare un blocco è che la sessione che lo ha acquisito lo rilasci (generalmente terminando la transazione) o che la sessione che lo ha acquisito venga terminata. Se l'applicazione client è ancora in esecuzione ma non esegue alcuna operazione per rilasciare il blocco o terminare la sessione, il blocco verrà mantenuto a tempo indeterminato. Un DBA dovrebbe terminare esplicitamente la sessione, lasciando che la transazione torni indietro e rilasciando il blocco per far ripartire il sistema. Se l'applicazione client smette di funzionare o, almeno, smette di rispondere (non sono ancora chiaro esattamente quale scenario di errore stai discutendo), è possibile che abiliti il rilevamento della connessione morta (DCD) tramite il Parametro 'SQLNET.EXPIRE_TIME' a livello di database farebbe sì che il database determini che il client non risponde e chiuda automaticamente la sessione, annullando la transazione e rilasciando il blocco.
Se sono presenti più sessioni di elaborazione dei dati, tuttavia, è generalmente preferibile utilizzare una qualche forma di blocco ottimistico. Altrimenti, stai progettando un sistema che avrà inevitabilmente bisogno del DBA per trovare e terminare con urgenza le sessioni per far funzionare nuovamente gli utenti aziendali e che richiederà sempre più interventi man mano che diventa più occupato. Non è qualcosa che i DBA amano fare e non è qualcosa di cui gli utenti aziendali si divertono a lamentarsi. Un semplice schema di blocco ottimistico sarebbe qualcosa come
- Seleziona una chiave da elaborare e una sorta di data che indichi l'ultimo aggiornamento della riga.
- Aggiorna una colonna di stato su "elaborazione" in modo che altre sessioni non tentino di elaborare la stessa riga.
- Elabora la voce nella tua domanda
- Al termine dell'elaborazione, aggiorna i dati utilizzando la chiave e l'ora selezionata nel primo passaggio. Se aggiorni 1 riga, sai che nessun'altra sessione ha modificato i dati in questione da quando l'hai selezionato. Se aggiorni 0 righe, sai che qualche altra sessione ha modificato i dati da quando li hai selezionati.
Con questo tipo di architettura, è relativamente facile interrogare il database per vedere quali righe vengono elaborate e, ad esempio, avere un lavoro che reimposta la colonna di stato su "non elaborata" dopo un certo periodo di tempo se il client non ha finito. È relativamente facile per le altre sessioni scegliere una riga diversa da elaborare. Ed è relativamente sicuro se, ad esempio, l'applicazione si blocca per un paio d'ore e poi si ripristina poiché scopre appena una volta terminata l'elaborazione che qualche altra sessione ha già rielaborato la riga.