有没有办法可以测试一行是否已被锁定以便在Oracle中进行更新?
例如,假设由一个用户执行以下查询:
select * from SOME_TABLE where THE_ID = 1000 for update;
对于另一个用户,我想检查THE_ID = 1000
的行是否被锁定。如果我尝试更新或某些东西,第二个用户被阻止并继续等待(不想那样)。
我还尝试与第二个用户运行以下查询:
select * from SOME_TABLE where THE_ID = 1000 for update NOWAIT;
由于我无法在同一行上放置两个锁,因此会失败。确实如此。我得到一个“ORA-00054:资源忙,并通过NOWAIT指定的错误获取”。我是否可以始终指望此错误来检查是否存在锁定,或者是否有更简单,更清晰的方法来确定行是否已被锁定?
谢谢!
答案 0 :(得分:15)
您可以使用FOR UPDATE NOWAIT编写一个过程,并在该行被锁定时返回错误消息:
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
现在让我们构建一个包含两个会话的小例子:
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
答案 1 :(得分:1)
既不简单也不干净,但V$LOCK
和V$SESSION
次观看了这些信息。
但是,如果您觉得需要使用此类内容作为正常应用程序代码的一部分,则需要重新考虑。应用程序不应该关心数据库如何锁定。如果您遇到死锁,则需要重新构建查询,以免它们发生。