【问题标题】:How can I lock a single row in Oracle SQL如何在 Oracle SQL 中锁定单行
【发布时间】:2016-04-18 23:23:24
【问题描述】:

这似乎很简单,但我很难做到。问题是如何使用 JOB_ID = IT_PROG 锁定表 JOBS 中的单行。我想这样做,因为我想尝试一个过程中的异常,当您尝试更新锁定的行时,它会向您显示一条消息。提前感谢您的宝贵时间。

【问题讨论】:

    标签: sql oracle row locked


    【解决方案1】:

    无法在 Oracle 中手动锁定行。不过,您可以手动锁定对象。执行 DML 操作时会自动在该行上放置排他锁,以确保没有其他会话可以更新同一行或任何其他 DDL 操作可以删除该行 - 其他会话可以随时读取它。

    请求对行锁定的第一个会话获得它,并且任何其他请求写访问权限的会话必须等待。
    如果你不想被锁定,也就是说,如果你不想等待,你可以使用

    Select .... For update ( nowait / wait(n) ) ( skiplocked)声明

    【讨论】:

    • 您的第一句话即使不是完全错误,也极具误导性。如果您不想投反对票,我建议您澄清或删除您的答案。
    【解决方案2】:

    您可以按照其他答案中的说明锁定记录,但在更新此行时您将看不到任何异常

    UPDATE 语句将等到锁被释放,即带有SELECT ... FOR UPDATE 的会话提交。之后将执行 UPDATE。

    您可以管理的唯一例外是死锁,即

    Session1   SELECT FOR UPDATE record A
    Session2   SELECT FOR UPDATE record B
    Session1   UPDATE record B  --- wait as record locked
    Session2   UPDATE record A  --- deadlock as 1 is waiting on 2 and 2 waiting on 1
    

    【讨论】:

    • 获得排他行锁。有没有办法“手动”获取为事务维护的共享行锁?
    • 您可以在共享模式下lock the whole table
    • 好的,有什么方法可以在共享模式下锁定一行?
    • 我不知道。但试着解释你为什么需要它。 Oracle 知道 readers 不会阻止 writers 您以某种方式尝试实现@PatrickSzalapski
    • 对,我是说我想要某个插入操作来阻止读者,直到它被提交。我知道它不会阻止读取表中的其他行,但会阻止包含新未提交行的聚合。
    【解决方案3】:

    AskTom 有一个您正在尝试做的示例:

    https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4515126525609

    来自 AskTom:

        declare
                resource_busy   exception;
                pragma exception_init( resource_busy, -54 );
                success boolean := False;
        begin
    
            for i in 1 .. 3
            loop
                 exit when (success);
                 begin
                             select xxx from yyy where .... for update NOWAIT;
                             success := true;
                 exception
                             when resource_busy then
                                     dbms_lock.sleep(1);
                 end;
             end loop;
    
             if ( not success ) then
                         raise_application_error( -20001, 'row is locked by another session' );
             end if;
        end;
    

    这会尝试获得一个锁,如果它无法获得一个(即 ORA-00054:资源繁忙并使用指定的 NOWAIT 获取或引发超时过期),它将引发错误。

    【讨论】:

    • 是的,谢谢您的回答。我已经完成了 PRAGMA 异常。我只需要锁定一行来查看 PRAGMA 是否真的有效。
    • 明白。如果您的选择语句返回单行,则 select for update 将锁定单行。给它一个唯一的 ID 或者你想要锁定的 rowid。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-19
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多