Voglio creare uno script in cui le sessioni di Oracle che entrano in un deadlock vengono uccise automaticamente
MODIFICA Spiegato in modo migliore, corretto alcune frasi e aggiunto un test case per dimostrare lo scenario di deadlock.
Perché vuoi reinventare la ruota? Oracle rileva automaticamente un deadlock, genera ORA-00060: deadlock detected while waiting for resource
e annulla una delle transazioni coinvolte nello stallo che Oracle ha deciso come vittima. Le precedenti transazioni riuscite non vengono annullate. Anche dopo l'errore di deadlock, se viene emesso un commit, verrà eseguito il commit della precedente transazione riuscita. A questo punto, anche la transazione dell'altra sessione avrà esito positivo e potresti emettere un commit. Non c'è niente che devi fare esplicitamente qui. I deadlock vengono automaticamente cancellati:non è mai necessario cancellare loro.
Di solito, Oracle impiega un secondo o due per rilevare un deadlock e genera l'errore.
Puoi provare con un semplice test case come mostrato qui:Capire Oracle Deadlock
Diamo un'occhiata a un test case -
SQL> CREATE TABLE t_test(col_1 NUMBER, col_2 NUMBER);
Table created
SQL> INSERT INTO t_test VALUES(1,2);
1 row inserted
SQL> INSERT INTO t_test VALUES(3,4);
1 row inserted
SQL> COMMIT;
Commit complete
SQL> SELECT * FROM t_test;
COL_1 COL_2
---------- ----------
1 2
3 4
Prendi nota dell'ora di ogni transazione, ho impostato il tempo per una migliore comprensione.
SESSIONE:1
12:16:06 SQL> UPDATE t_test SET col_1 = 5 WHERE col_2=2;
1 row updated.
Elapsed: 00:00:00.00
SESSIONE:2
12:16:04 SQL> UPDATE t_test SET col_1 = 6 WHERE col_2=4;
1 row updated.
Elapsed: 00:00:00.00
12:16:31 SQL> UPDATE t_test SET col_1 = 7 WHERE col_2=2;
A questo punto, la SESSIONE 2 continua ad aspettare .
SESSIONE:1
12:16:15 SQL> UPDATE t_test SET col_1 = 8 WHERE col_2=4;
A questo punto, SESSIONE 2 è vittima di una situazione di stallo, SESSIONE 1 sta ancora aspettando.
Diamo un'occhiata ai dettagli della sessione di SESSIONE 2 -
12:22:15 SQL> select sid,status,program,sql_id, state, wait_class, blocking_session_status, event from v$session where schemaname='LALIT' and program='sqlplus.exe';
SID STATUS PROGRAM SQL_ID STATE WAIT_CLASS BLOCKING_SE EVENT
---------- -------- --------------- ------------- ------------------- --------------- ----------- ----------------------------------------------------------------
14 ACTIVE sqlplus.exe 60qmqpmbmyhxn WAITED SHORT TIME Network NOT IN WAIT SQL*Net message to client
134 ACTIVE sqlplus.exe 5x0zg4qwus29v WAITING Application VALID enq: TX - row lock contention
Elapsed: 00:00:00.00
12:22:18 SQL>
Quindi, v$session
dettagli se visualizzati nella SESSIONE 2 , ovvero SID 14, dice che lo stato è ACTIVE .
Diamo un'occhiata ai dettagli della sessione di un'altra sessione, chiamiamola SESSIONE 3 per il bene. Ricorda, SESSIONE 1 sta ancora aspettando.
SQL> set time on timing on
12:24:41 SQL> select sid,status,program,sql_id, state, wait_class, blocking_session_status, event from v$session where schemaname='LALIT' and program='sqlplus.exe'
SID STATUS PROGRAM SQL_ID STATE WAIT_CLASS BLOCKING_SE EVENT
---------- -------- --------------- ------------- ------------------- ---------- ----------- ------------------------------
13 ACTIVE sqlplus.exe 60qmqpmbmyhxn WAITED SHORT TIME Network NOT IN WAIT SQL*Net message to client
14 INACTIVE sqlplus.exe WAITING Idle NO HOLDER SQL*Net message from client
134 ACTIVE sqlplus.exe 5x0zg4qwus29v WAITING Applicatio VALID enq: TX - row lock contention
n
Elapsed: 00:00:00.01
12:24:44 SQL>
Quindi, per le altre sessioni, SESSIONE 2 , ovvero SID 14, è INATTIVO . SESSIONE 1 è ancora IN ATTESA con l'evento enq: TX - row lock contention
.
Impegniamo la SESSIONE 2 -
12:22:18 SQL> commit;
Commit complete.
Elapsed: 00:00:00.01
12:25:43 SQL>
A questo punto, il blocco viene rilasciato per la SESSIONE 1 , impegniamo anche la sessione 1 -
12:16:15 SQL> UPDATE t_test SET col_1 = 8 WHERE col_2=4;
1 row updated.
Elapsed: 00:08:27.29
12:25:43 SQL> commit;
Commit complete.
Elapsed: 00:00:00.00
12:26:26 SQL>
Elapsed: 00:08:27.29
mostra SESSIONE 1 stava aspettando da così tanto tempo fino alla SESSIONE 2 è stato commesso.
Per riassumere, ecco l'intera storia della sessione 1 -
12:16:06 SQL> UPDATE t_test SET col_1 = 5 WHERE col_2=2;
1 row updated.
Elapsed: 00:00:00.00
12:16:15 SQL> UPDATE t_test SET col_1 = 8 WHERE col_2=4;
1 row updated.
Elapsed: 00:08:27.29
12:25:43 SQL> commit;
Commit complete.
Elapsed: 00:00:00.00
12:26:26 SQL>
Per riassumere, ecco l'intera storia della sessione 2 -
12:16:04 SQL> UPDATE t_test SET col_1 = 6 WHERE col_2=4;
1 row updated.
Elapsed: 00:00:00.00
12:16:31 SQL> UPDATE t_test SET col_1 = 7 WHERE col_2=2;
UPDATE t_test SET col_1 = 7 WHERE col_2=2
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
Elapsed: 00:00:24.47
12:22:15 SQL> select sid,status,program,sql_id, state, wait_class, blocking_session_status, event from v$session where schemaname='LALIT' and program='sqlplus.exe';
SID STATUS PROGRAM SQL_ID STATE WAIT_CLASS BLOCKING_SE EVENT
---------- -------- --------------- ------------- ------------------- --------------- ----------- ----------------------------------------------------------------
14 ACTIVE sqlplus.exe 60qmqpmbmyhxn WAITED SHORT TIME Network NOT IN WAIT SQL*Net message to client
134 ACTIVE sqlplus.exe 5x0zg4qwus29v WAITING Application VALID enq: TX - row lock contention
Elapsed: 00:00:00.00
12:22:18 SQL> commit;
Commit complete.
Elapsed: 00:00:00.01
12:25:43 SQL>
Ora, vediamo quale transazione è stata effettivamente annullata e quale impegnata -
12:25:43 SQL> select * from t_test;
COL_1 COL_2
---------- ----------
5 2
8 4
Elapsed: 00:00:00.00
12:30:36 SQL>
Conclusione
A mio parere, il modo migliore per conoscere i dettagli della sessione di un deadlock è registrare i dettagli nel modo più dettagliato possibile. Altrimenti, è un incubo per un DBA indagare senza informazioni adeguate registrate. Del resto, anche uno sviluppatore troverebbe un compito arduo correggere e correggere l'effettivo difetto di progettazione se i dettagli dell'errore di deadlock non vengono registrati in modo dettagliato. E per concludere con un'affermazione di una riga, un punto morto è dovuto a un difetto di progettazione, Oracle è solo la vittima e l'applicazione è il colpevole. I deadlock fanno paura, ma sottolineano i difetti di progettazione che prima o poi devono essere corretti.