代码之家  ›  专栏  ›  技术社区  ›  user159088

如何检查是否为更新而锁定了行?

  •  7
  • user159088  · 技术社区  · 15 年前

    在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:resource busy and acquire with nowait specified error”。我是否可以始终依赖此错误来检查是否存在锁,或者是否有一种更简单、更清晰的方法来确定行是否被锁定?

    谢谢您!

    2 回复  |  直到 14 年前
        1
  •  15
  •   Vincent Malgrat    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
    
        2
  •  1
  •   kdgregory    15 年前

    它既不简单也不干净,但信息可在 V$LOCK V$SESSION 意见。

    但是,如果您觉得有必要将类似这样的代码作为正常应用程序代码的一部分,那么您需要重新考虑。应用程序不应该关心数据库如何锁定。如果您遇到了死锁,您需要重新构造查询,以便它们不会发生。