【发布时间】:2016-04-18 23:23:24
【问题描述】:
这似乎很简单,但我很难做到。问题是如何使用 JOB_ID = IT_PROG 锁定表 JOBS 中的单行。我想这样做,因为我想尝试一个过程中的异常,当您尝试更新锁定的行时,它会向您显示一条消息。提前感谢您的宝贵时间。
【问题讨论】:
这似乎很简单,但我很难做到。问题是如何使用 JOB_ID = IT_PROG 锁定表 JOBS 中的单行。我想这样做,因为我想尝试一个过程中的异常,当您尝试更新锁定的行时,它会向您显示一条消息。提前感谢您的宝贵时间。
【问题讨论】:
无法在 Oracle 中手动锁定行。不过,您可以手动锁定对象。执行 DML 操作时会自动在该行上放置排他锁,以确保没有其他会话可以更新同一行或任何其他 DDL 操作可以删除该行 - 其他会话可以随时读取它。
请求对行锁定的第一个会话获得它,并且任何其他请求写访问权限的会话必须等待。
如果你不想被锁定,也就是说,如果你不想等待,你可以使用
Select .... For update ( nowait / wait(n) ) ( skiplocked)声明
【讨论】:
您可以按照其他答案中的说明锁定记录,但在更新此行时您将看不到任何异常。
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
【讨论】:
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 获取或引发超时过期),它将引发错误。
【讨论】: