【问题标题】:Select from table in Oracle with multiple sessions从具有多个会话的 Oracle 表中选择
【发布时间】:2009-10-02 18:15:32
【问题描述】:

我有多个线程正在处理同一个表中的行,该表实际上是一个队列。

我希望每一行仅由一个线程处理。因此,我添加了一个列 - “IsInProccess”,并在线程 SELECT 语句中添加了“WHERE IsInProccess = 0”。 此外,我使用“SELECT FOR UPDATE”,因此在一个线程从表中获取一行之后,在将 1 放入“IsInProccess”之前,没有其他线程会得到它。

问题是我有很多线程,并且很多时候会发生以下情况: 线程 A 通过“SELECT FOR UPDATE”选择表格并获取行号。 1。在将 IsInProccess 更改为 1 之前,线程 B 以相同的方式从表中进行选择,并获得第 1 行。 Oracle 保存行号1 到线程 A 会话和线程 B 无法更改此行并返回错误 - “无法获取”。

我希望当某个线程从表中选择时,Oracle 将返回未保存到其他打开会话的行。

我可以这样做吗?

【问题讨论】:

    标签: oracle


    【解决方案1】:

    这是我之前看到使用非常成功的解决方案的草图:

    1. 使用 SELECT FOR UPDATE NOWAIT 语法,这样如果会话不能立即获得对行的锁定,它会引发异常而不是等待锁定。异常处理程序可能会等待几秒钟(例如,使用 dbms_lock.sleep);整个块可以被包裹在一个循环中,在它放弃之前再次尝试一定次数。

    2. 将 WHERE ROWNUM<=n 添加到查询中,以便它一次只尝试获取一定数量的行(例如 1);如果成功,将行更新为“处理中”。

    3. 将行标记为“正在处理”(我已经看到成功使用)的一种好方法是拥有两列 - SID 和 SERIAL# - 并使用当前的 SID 和 SERIAL# 更新这些列会议。

    4. 如果会话在将行标记为“处理中”时失败,另一个进程可以通过搜索任何具有 SID/SERIAL 的行来“清理”标记为“处理中”的行# 在v$session 中未发现的活动会话。

    【讨论】:

    • 杰弗里,感谢您的回答。 1. 我已经使用 SELECT FOR UPDATE NOWAIT。 2. 每条select语句只返回一行。 3. 这正是我现在正在实施的解决方案——我认为也许有更好的解决方案。
    • @Roy - 我认为不同之处在于您必须按照 Jeffrey 的概述处理异常
    • @Roy - 从您的问题来看,您使用会话的 sid/serial# 标记行并不明显。正如 dpbradley 所指出的,异常处理是这里的关键。
    【解决方案2】:

    Oracle 已经为您解决了这个问题:使用高级队列 API

    【讨论】:

      【解决方案3】:

      如果你有11g,看SKIP LOCKED 它在那里,但在 10g 中没有记录(因此不受支持并且可能存在错误)。 这样,当 Session A 锁定行时,Session B 可以跳过它并处理下一个。

      【讨论】:

      • 加里,只是想让你知道 - 我在工作中使用了你的小费,这很棒。我们不知道这个 Oracle 功能。谢谢。
      【解决方案4】:

      一种解决方案:

      1. 将选择和更新查询放入事务中。这类问题正是发明交易的原因。

      2. 您还需要担心“孤立”行 - 例如一根线拾起行,然后在未完成工作的情况下死亡。为了解决这个问题,一种解决方案是有 2 列:“IsInProcess”和“StartprocessingTime”。

        isInProcess 将有 3 个值:0(未处理)、1(已提取)、2(已完成)。

        原始事务会将行的“isInProcess”设置为 1,将“StartprocessingTime”设置为其他值,但 select 也会将此添加到 where 子句(假设您可以指定有效的超时时间)

        “WHERE isInProcess = 0 OR (isInProcess = 1 AND St​​artprocessingTime

        请注意,上面的语法不是 ORACLE,只是伪代码。

      【讨论】:

      • DVK - 我不明白您的解决方案“将选择和更新查询放入事务中”。你能解释一下吗?关于点号。 2 - 我知道这个问题,并在维护表的单独进程中处理它。
      猜你喜欢
      • 2011-12-09
      • 1970-01-01
      • 2019-11-09
      • 1970-01-01
      • 2017-12-15
      • 2012-12-07
      • 2020-05-28
      • 2013-06-23
      • 2010-10-11
      相关资源
      最近更新 更多