如何检查某行是否被锁定以进行更新?

发布于 2024-08-07 08:21:46 字数 489 浏览 10 评论 0原文

有没有一种方法可以测试 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 指定错误”。我是否可以始终依靠此错误来检查锁是否存在,或者是否有更简单、更清晰的方法来确定行是否被锁定?

谢谢你!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小傻瓜 2024-08-14 08:21:46

您可以使用 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

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
挽清梦 2024-08-14 08:21:46

它既不简单也不干净,但可以在 V$LOCKV$SESSION 视图中获取信息。

但是,如果您觉得需要在正常应用程序代码中使用类似的内容,则需要重新考虑。应用程序不应该关心数据库如何锁定。如果您遇到死锁,则需要重组查询以防止死锁发生。

It's neither simple nor clean, but the information is available in the V$LOCK and V$SESSION views.

However, if you feel the need to use something like this as part of your normal application code, you need to think again. Applications should not care about how the database does locking. If you're running into deadlocks, you need to restructure your queries so that they don't happen.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文