【问题标题】:Why we need SELECT FOR UPDATE in Oracle SQL?为什么我们在 Oracle SQL 中需要 SELECT FOR UPDATE?
【发布时间】:2021-02-17 17:55:21
【问题描述】:

请注意,我是 Oracle SQL 的新手。所以根据我对任何数据库的了解,有一些方法可以处理并发。所以我想澄清的是,就像我之前提到的,据我所知,当我们并行执行两个或多个事务时,数据库会自动自己弄清楚,如何并行处理这些事务(作为可序列化的调度)通过克服读写冲突(为了实现这个数据库使用锁定机制)。所以通过最终遵循所有这些机制,我知道数据库默认情况下会确保当我们同时运行两个或多个事务时,它们之间会有隔离。所以我的问题是,当事务之间总是存在隔离时(这意味着事务之间不会发生任何读写冲突)为什么我们仍然需要使用像SELECT FOR UPDATE这样的语句来锁定数据库中的任何数据。我的意思是为什么我们不能在事务块中继续我们想要的任何东西? 例如:

Begin transaction
//Queries
//commit
End transaction

【问题讨论】:

    标签: sql oracle relational-database oracle12c


    【解决方案1】:

    为什么我们不能在事务块中继续我们想要的任何东西?

    因为在 Oracle 中,readers don't block writers。如果您从表中select,您不会锁定它并且没有事务。所以,假设你这样做:

    select col1, col2 into l_col1, l_col2
    from table1
    where ...;
    
    if (<some logic based on l_col2`) then
      update table1 set col2 = something where col1 = l_col1;
    end if;
    

    没关系;但是如果两个会话同时运行该代码,一个会话可能会更新 之间的行,而另一个会话选择并执行其更新 - 导致更新丢失或逻辑不正确,因为状态实际上并非如此正如预期的那样。

    如果你改为select ... for update:

    select col1, col2 into l_col1, l_col2
    from table
    where ...
    for update;  -- or: for update of col2
    
    if (<some logic based on l_col2`) then
      update table1 set col2 = something where col1 = l_col1;
    end if;
    

    那么当第一个会话select for update 时,表锁定,因此第二个会话必须等待该事务完成才能获得锁,它会看到第一次更新应用之后行的状态。没有丢失更新,没有混乱。

    您也可以锁定不想更新的行,正如the documentation 所说:

    带有FOR UPDATE 子句的SELECT 语句(SELECT FOR UPDATE 语句)选择结果集中的行并锁定它们。 SELECT FOR UPDATE 允许您基于行中的现有值进行更新,因为它确保在您更新它们之前没有其他用户可以更改这些值。您还可以使用SELECT FOR UPDATE 锁定您不想更新的行,如示例 9-6 所示。

    你可以调整行为:

    默认情况下,SELECT FOR UPDATE 语句会一直等待,直到获得请求的行锁。要更改此行为,请使用SELECT FOR UPDATE 语句的NOWAITWAITSKIP LOCKED 子句。有关这些子句的信息,请参阅 Oracle 数据库 SQL 语言参考。

    如果select for update 在游标循环中,那么它也允许您这样做

      update table1 set col2 = something where current of <cursor>;
    

    SELECT FOR UPDATE 与显式游标相关联时,该游标称为FOR UPDATE 游标。只有FOR UPDATE 游标可以出现在UPDATEDELETE 语句的CURRENT OF 子句中。 (CURRENT OF 子句是 SQL 语句 UPDATEDELETEWHERE 子句的 PL/SQL 扩展,将语句限制为游标的当前行。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-08
      • 1970-01-01
      • 1970-01-01
      • 2019-06-09
      • 2017-12-05
      • 2017-03-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多