Sql – How to check if a row is locked for update

ora-00054oraclesql

Is there a way that one can test if a row has been locked for update in Oracle?

As an example, suppose the following query, performed by one user:

select * from SOME_TABLE where THE_ID = 1000 for update;

With another user I want to check if the row with THE_ID = 1000 is locked. If I try an update or something the second user gets blocked and remains waiting (do not want that).

I have also tried running the following query with the second user:

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

Since I can not place two locks on the same row this will fail. And it does. I get an "ORA-00054: resource busy and acquire with NOWAIT specified error". Can I always count on this error to check the presence of the lock, or is there a simpler and cleaner way of determining if a row is locked?

Thank you!

Best Answer

You can write a procedure with the FOR UPDATE NOWAIT and return an error message when the row is locked:

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

Now let's build a small example with two sessions:

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