当前位置: 首页 > 知识库问答 >
问题:

建议锁还是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.

我只想让我的查询找到并更新第一行(随机地,用< code>LIMIT),其中< code>available = true并将其更新为< code>available = false,我需要在执行此操作的同时锁定该行,但不需要发出新的请求来等待前一个锁的释放,因为有许多并发调用将使用该查询。

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

> NOWAIT的目标是:

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

< code > pg _ try _ advisory _ xact _ lock 的目标< br >不是等待上一个事务释放锁,仍然能够执行另一个事务,并且只操作下一个select以更新“尚未锁定”的行。

哪一个更适合我的需求?

共有1个答案

孔斌
2023-03-14

对于更新 NOWAIT 只有当您坚持锁定特定行时才是一个好主意,这不是您所需要的。您只需要任何符合条件的可用(未锁定)行。重要的区别在于这一点(引用Postgres 9.4的手册):

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

相同的查询很可能会尝试锁定相同的任意选择。For UPDATE NOWAIT只会在异常情况下退出(除非您捕获错误,否则它将回滚整个事务)并且您必须重试。

我在 dba.SE 参考答案中的解决方案使用普通 FOR UPDATEpg_try_advisory_lock() 的组合:

pg_try_advisory_lock类似于pg_advisory_lock,只是该功能不会等待锁可用。它将立即获取锁并返回 true,或者如果无法立即获取锁,则返回 false。

所以你最好的选择是...第三种选择:Postgres 9.5中新的< code>FOR UPDATE SKIP LOCKED,它实现了相同的行为,而没有额外的函数调用。

Postgres 9.5的手册比较了这两个选项,解释了更多的区别:

若要防止操作等待其他事务提交,请使用 NOWAITSKIP LOCK 选项。使用 NOWAIT,如果无法立即锁定所选行,则语句将报告错误,而不是等待。使用 SKIP LOCKED,任何无法立即锁定的选定行都将被跳过。

在Postgres 9.4或更高版本上,您的下一个最佳选择是将pg_try_advisory_xact_lock(id)FOR UPDATE结合使用,如参考答案所示:

  • Postgres更新…限制1

(还使用带有FORUPDATE SKIP LOCKED的实现。)

严格来说,你会得到任意的,而不是真正的随机选择。这可能是一个重要的区别。
您的查询的审核版本在我对另一个问题的回答中。

 类似资料:
  • 问题内容: 在我的Rails 4应用程序中,我将查询查询到Postgres 9.4 数据库: dba.SE上的相关答案极大地启发了我们。 我只希望查询在其中找到并更新第一行(并将其随机更新为),然后将其更新为,而我需要在执行此操作时锁定该行,但无需发出新的请求来等待释放先前的锁,因为许多将使用此查询的 并发调用 。 但我也看到了选择。我不确定我是否理解使用和选项之间的区别,在我看来它们似乎可以实现

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

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

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

  • 本文向大家介绍什么是线程死锁?如何避免死锁?相关面试题,主要包含被问及什么是线程死锁?如何避免死锁?时的应答技巧和注意事项,需要的朋友参考一下 认识线程死锁 多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。 如下图所示,线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,所以这两个线程就会互相等待而进入死锁状态

  • 问题内容: 最近几天,随机地,我的网站变得非常缓慢。我开始尽力调查。我看到MySQL进程正在使用服务器可用内存的85%-95%(我也应该升级我的内存吗?)。 我检查了我的MySQL进程日志,发现有很多查询,其中包括: 等待表级锁定 但是我还注意到,所有这些带有“表级锁定”的查询都是与表有关的查询。 我还有20个其他表,它们具有不变的查询,但是我在列表中没有看到它们。.所以我猜问题出在users表上