【问题标题】:Oracle SELECT FOR UPDATE - Demonstration?Oracle SELECT FOR UPDATE - 演示?
【发布时间】:2017-12-05 13:11:33
【问题描述】:

我不太了解 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 表中的行吗?

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

【问题讨论】:

  • 锁只阻止更新或删除,不阻止选择
  • 好的,但是,有没有办法在单个脚本文件中演示锁定?如果我选择更新然后进行两次更新,它当然会允许两次更新,因为我请求选择更新。可能有 2 个事务同时运行?
  • 在您创建 commit之前,其他会话不会看到更改者
  • 我不清楚你到底想“展示”什么 - 但要测试/展示锁定和并发性,你至少需要 两个 数据库会话(事务) - 你single 脚本无法做到这一点。
  • @a_horse_with_no_name - 实际上我们可以演示它。看我的回答

标签: sql oracle transactions locking


【解决方案1】:

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

【讨论】:

  • 完美答案!
【解决方案2】:

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

“好的,但是,有没有办法在单个脚本文件中演示锁定?”

是的。这是一个带有本地过程的脚本,它使用autonomous_transaction pragma 来模拟多用户环境:

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> 

【讨论】:

  • 我有一个问题要问您,希望您能解答。最初的问题是关于SELECT FOR UPDATE,它涉及显式锁定。所以假设我们做SELECT FOR UPDATE而不是update t23,你将如何开始另一个自治事务(调用p1而不首先释放锁。第二个问题:如果你在释放锁之前设法启动另一个AT t23,会不会导致死锁,因为主事务仍然持有排他锁?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
  • 2016-04-11
  • 2015-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多