2009-10-15 16 views
7

Esiste un modo per testare se una riga è stata bloccata per l'aggiornamento in Oracle?Come si controlla se una riga è bloccata per l'aggiornamento?

Come esempio, si supponga la seguente query, eseguita da un utente:

select * from SOME_TABLE where THE_ID = 1000 for update; 

Con un altro utente voglio verificare se la riga con THE_ID = 1000 è bloccato. Se provo un aggiornamento o qualcosa del genere, il secondo utente viene bloccato e rimane in attesa (non lo voglio).

Ho anche provato eseguendo la seguente query con il secondo utente:

select * from SOME_TABLE where THE_ID = 1000 for update NOWAIT; 

Poiché non posso collocare due fermi sulla stessa riga fallirà. E lo fa. Ottengo un "ORA-00054: risorsa occupata e acquisita con l'errore specificato NOWAIT". Posso sempre contare su questo errore per verificare la presenza del blocco, oppure esiste un modo più semplice e pulito per determinare se una riga è bloccata?

Grazie!

+1

si dovrebbe ottieni questo errore "ORA-00054: risorsa occupata e acquisita con NOWAIT specificato" - sei sicuro che il tuo utente possa vedere la tabella? – SeriousCallersOnly

+0

@ SeriousCallersOnly: Grazie, in effetti sto avendo "ORA-00054: risorsa occupata e acquisita con l'errore specificato NOWAIT". L'ORA-00942 è stato lanciato da un altro strato della mia app. Mi dispiace per quello Modificherò la domanda. –

risposta

14

È possibile scrivere una procedura con il FOR UPDATE NOWAIT e restituire un messaggio di errore quando la riga è bloccata:

SQL> CREATE OR REPLACE PROCEDURE do_something(p_id NUMBER) IS 
    2  row_locked EXCEPTION; 
    3  PRAGMA EXCEPTION_INIT(row_locked, -54); 
    4 BEGIN 
    5  FOR cc IN (SELECT * 
    6     FROM some_table 
    7     WHERE ID = p_id FOR UPDATE NOWAIT) LOOP 
    8  -- proceed with what you want to do; 
    9  NULL; 
10  END LOOP; 
11 EXCEPTION 
12  WHEN row_locked THEN 
13  raise_application_error(-20001, 'this row is locked...'); 
14 END do_something; 
15/

Procedure created 

Ora costruiamo un piccolo esempio con due sessioni:

session_1> select id from some_table where id = 1 for update; 

     ID 
---------- 
     1 

session_2> exec do_something(1); 

begin do_something(1); end; 

ORA-20001: this row is locked... 
ORA-06512: at "VNZ.DO_SOMETHING", line 11 
ORA-06512: at line 2 

session_1> commit; 

Commit complete 

session_2> exec do_something(1); 

PL/SQL procedure successfully completed 
+0

Come ho già risposto a SeriousCallersOnly ho davvero l'errore ORA-00054. Grazie. Ma posso contare su di esso per verificare la serratura? –

+0

@dpb: puoi contare su questo meccanismo. Ho aggiunto un piccolo esempio che mostra come la procedura avrebbe funzionato con due sessioni bloccando la stessa riga. –

1

Non è né semplice né pulito, ma le informazioni sono disponibili nelle viste V$LOCK e V$SESSION.

Tuttavia, se si sente la necessità di utilizzare qualcosa come questo come parte del normale codice dell'applicazione, è necessario ripensarci. Le applicazioni non dovrebbero preoccuparsi di come il database si blocca. Se si verificano deadlock, è necessario ristrutturare le query in modo che non si verifichino.

Problemi correlati