当前位置: 首页 > 面试题库 >

建议性锁定还是NOWAIT以避免等待锁定的行?

廉元龙
2023-03-14
问题内容

在我的Rails 4应用程序中,我将查询查询到Postgres 9.4 数据库:

@chosen_opportunity = Opportunity.find_by_sql(
  " UPDATE \"opportunities\" s
    SET opportunity_available = false
    FROM (
          SELECT \"opportunities\".*
          FROM   \"opportunities\"
          WHERE  ( deal_id = #{@deal.id}
          AND    opportunity_available = true 
          AND    pg_try_advisory_xact_lock(id) )
          LIMIT  1
          FOR    UPDATE
          ) sub
    WHERE       s.id = sub.id
    RETURNING   sub.prize_id, sub.id"
)

dba.SE上的相关答案极大地启发了我们。

我只希望查询在其中找到并更新第一LIMIT行(available = true并将其随机更新为),然后将其更新为available = false,而我需要在执行此操作时锁定该行,但无需发出新的请求来等待释放先前的锁,因为许多将使用此查询的 并发调用

但我也看到了NOWAIT选择FOR UPDATE。我不确定我是否理解使用pg_try_advisory_xact_lock()NOWAIT选项之间的区别,在我看来它们似乎可以实现相同的目标:

  • NOWAIT的目标:

为防止该操作等待其他事务提交,请使用该NOWAIT选项。

  • pg_try_advisory_xact_lock的目标
    不是等待上一个事务释放锁定,而是仍然能够执行另一个事务,并且仅操作下一个select来更新“尚未锁定”的行。

哪一个更适合我的需求?


问题答案:

FOR UPDATE NOWAIT 如果您坚持锁定特定的行,这 不是 一个好主意,那 不是
您所需要的。您只需要 任何 符合条件的可用(解锁)行。重要的区别是此(引用Postgres
9.4手册
):

使用NOWAIT,如果无法立即锁定选定的行,该语句将报告错误,而不是等待。

相同的查询很可能会尝试锁定相同的任意选择。FOR UPDATE NOWAIT只会因出现异常而纾困(除非捕获错误,否则它将回滚整个事务),您必须重试。

我在dba.SE上引用的答案中的解决方案结合使用了plain FOR UPDATE 和以下内容
pg_try_advisory_lock()

pg_try_advisory_lock与相似pg_advisory_lock,不同之处在于该功能将不等待锁变为可用。它将立即获取锁并返回true,或者如果无法立即获取锁,则返回false。

因此, 最好的选择 是……第三种选择: FOR UPDATE SKIP LOCKED Postgres
9.5中的新功能,它实现了相同的行为,而没有额外的函数调用。

Postgres 9.5的手册比较了这两个选项,并进一步说明了不同之处:

为防止操作等待其他事务提交,请使用NOWAITSKIP LOCKED选项。使用NOWAIT,如果无法立即锁定选定的行,该语句将报告错误,而不是等待。使用SKIP LOCKED,将跳过所有不能立即锁定的选定行。

在Postgres 9.4或更早的版本上,您的 下一个最佳选择pg_try_advisory_xact_lock(id)FOR UPDATE参考答案中所示的类似物组合使用:

  • Postgres UPDATE-LIMIT 1

(还带有的实现FOR UPDATE SKIP LOCKED。)

在旁边

严格来说,您会得到任意选择,而不是真正的随机选择。



 类似资料:
  • 在我的Rails 4应用程序中,我有一个对Postgres 9.4数据库的查询: 很受这个相关回答的启发dba.SE. 我只想让我的查询找到并更新第一行(随机地,用< code>LIMIT),其中< code>available = true并将其更新为< code>available = false,我需要在执行此操作的同时锁定该行,但不需要发出新的请求来等待前一个锁的释放,因为有许多并发调用将

  • 问题内容: 更新记录时,我反复出现锁定超时超出异常的情况。 我正在使用Java Struts 2.1 Hibernate配置。使用的数据库是MYSQL。 任何人都知道如何解决它。 问题答案: 这里有一些建议: “ 锁定等待超时 ”通常发生在事务正在等待要更新的数据行上,而该行已被某些其他事务锁定时。 在大多数情况下,问题出在数据库方面。可能的原因可能是表格设计不当,数据量大,约束等。 请查看这个详

  • 主要内容:示例资源分配图是系统状态的图形表示。 顾名思义,资源分配图是关于持有一些资源或等待某些资源的所有进程的完整信息。 它还包含有关所有资源的所有实例的信息,无论这些资源是否可用或正在被进程使用。 在资源分配图中,进程由圆形表示,而资源由矩形表示。 我们来详细看看顶点和边的类型。 顶点主要有两种类型,资源和过程。 它们中的每一个将以不同的形状表示。 Circle代表进程,而矩形代表资源。 一个资源可以有多个

  • 在避免死锁的情况下,如果系统的结果状态不会导致系统中的死锁,那么将会授予对任何资源的请求。系统的状态将持续检查安全和不安全的状态。 为了避免死锁,进程必须告诉OS,进程可以请求完成其执行的最大资源数量。 最简单和最有用的方法指出,流程应声明它可能需要的每种类型的最大资源数量。 死锁避免算法检查资源分配,以便永远不会有循环等待条件。 安全和不安全的状态 系统的资源分配状态可以由可用资源和已分配资源的

  • 问题内容: 我在这里思考:如果您有2个线程执行需要同步的FAST操作,那么非阻塞方法不是比阻塞/上下文切换方法更快/更好的方法吗? 非阻塞的意思是: while(true){如果(checkAndGetTheLock())中断;} 如果您有太多线程在锁中循环,我唯一想到的就是饥饿(CPU耗尽)。 如何平衡一种方法与另一种方法? 问题答案: 以下是 Java Concurrency in Pract

  • 我认为这是一个常见的问题,但我还没有找到任何解决方案,也许我没有在谷歌上正确地搜索这个问题。总之,我有一个在表中插入多行的过程(在同一个事务中的许多其他事情中),但是这个过程是在多个线程和多个服务器中执行的。 描述是唯一的,但不作为数据库(旧版)中的约束,我想避免插入重复的描述。我已经隔离了搜索并插入到一个独立的事务中,我想在选择之前锁定表,如果它不存在,则在“保存”之后释放它。 我想要这样的东西