2017-07-01 41 views
1

我完全不理解SELECT FOR UPDATE的锁定功能。Oracle SELECT FOR UPDATE - 演示?

这是我试过的。

CREATE TABLE ACCOUNT_TAB (
    ACC_ID int NOT NULL PRIMARY KEY, 
    BALANCE int NOT NULL 
); 

INSERT INTO ACCOUNT_TAB 
VALUES(1, 100); 

SELECT * FROM ACCOUNT_TAB FOR UPDATE; 
SELECT * FROM ACCOUNT_TAB; 

两个SELECT都将检索该行,但不应该第一个查询锁定ACCOUNT_TAB表中的行吗?

我已阅读了有关会话的内容:来自同一个会话的查询并不关心锁定。我可以以某种方式在单个脚本文件中演示锁定功能吗?例如,我可以在一个脚本中运行两个不同的会话,所以第二个调用将检索一个错误,指出该行已被锁定?

+3

锁定只是阻止更新或删除,而不是选择 –

+0

好了,但仍是有一些方法来证明在一个脚本文件上的锁?如果我选择更新,然后执行两个更新,则当然会允许这两个更新,因为我请求选择进行更新。也许有可能同时运行2个交易? – Max

+0

其他会话将不会看到转换器,直到您提交'commit' – are

回答

3

您的原始实验未能证明锁定,因为在Oracle中写入不会阻止读取。 FOR UPDATE子句允许我们避免两个会话尝试写入同一记录的情况;任何数量的会话都可以读取记录。 “

”好吧,但仍然有一些方法可以演示单个脚本文件中的锁定吗?“

是。这里是一个局部过程,它使用autonomous_transaction编译来模拟多用户环境的脚本:

declare 
    procedure p1 (p_id in number) is 
     pragma autonomous_transaction; 
     cursor c23 is 
      select * from t23 
      where id = p_id 
      for update nowait; 
     r23 c23%rowtype; 
    begin 
     dbms_output.put_line('nested transaction'); 
     open c23; 
     fetch c23 into r23; 
     update t23 
     set col2 = col2 * 2; 
     close c23; 
     commit; 
    exception 
     when others then 
      dbms_output.put_line(sqlerrm); 
    end; 

begin 
    update t23 
    set col1 = 2 
    where id = 1; 

    p1 (1); 

    commit; 
end; 
/

第一个UPDATE语句发出的锁,这会导致程序调用失败,因为它不能获得锁定(由于使用NOWAIT子句):

... 
    30 end; 
    31/
nested transaction 
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired 

PL/SQL procedure successfully completed. 

SQL> 
+0

我有一个问题给你,我很感激你的回答。原来的问题是关于'SELECT FOR UPDATE',涉及显式锁定。所以我们假设我们使用'SELECT FOR UPDATE'而不是'update t23',你将如何启动另一个自治事务(在不释放锁定的情况下调用'p1')。第二个问题:如果你之前设法启动另一个AT释放't23'上的锁定,是不是会导致死锁,因为主交易剧照仍然拥有独占锁定? – fg78nc

1

RDBMS将在SELECT FOR UPDATE语句标识的所有行上获得独占的行级锁,因此只有您是唯一允许更新它们的行。这意味着除非您执行COMMIT或ROLLBACK,否则其他RDBMS客​​户端将无法更改任何此记录。因此,如果要测试它的工作方式,请创建两个单独的客户端连接,并首先尝试在一个会话中锁定记录,然后尝试在另一个会话中更新相同的记录。