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

postgres SELECT FORUPDATE中的锁定顺序

汪翰墨
2023-03-14

假设表 ab 都有一行,则查询

 SELECT * FROM a, b FOR UPDATE

应该有两个行级锁(一个在 A 上,一个在 B 上)。是否有任何定义的顺序来获取锁?有没有办法要求表 b 中的锁在来自 a 的锁之前获得锁定(以避免与其他事务死锁)?

共有1个答案

呼延烈
2023-03-14

是否有任何定义的获取锁的顺序?

据我所知,对于SELECT*,无论如何。由于这种情况没有记录锁顺序,因此即使在实践中它存在,您也不能依赖它。它可能会在未来的版本中发生变化。

有没有办法要求表 b 中的锁在来自 a 的锁之前获得锁定(以避免与其他事务死锁)?

如果您必须使用< code>SELECT *,则不能。但如果您可以控制< code > SELECT -列表,则可以。看起来行锁是按照相关元组字段出现在< code>SELECT列表中的顺序获取的,因此:

SELECT a.x, b.x FROM b, a FOR UPDATE;

将从a获取行的锁,然后从b获取行。无论如何,此刻;我认为标准没有规定这一点,也没有在文档中看到对它的任何引用,因此这可能会在以后发生变化。

就我个人而言…我会使用DO块或单独的查询。使用一些子查询或CTE可能是可行的,但您必须在它们之间创建某种形式的人工依赖关系,以确保排序。脆弱,不值得。

让我们看看实际发生了什么:

regress=> EXPLAIN (VERBOSE) SELECT * FROM a, b FOR UPDATE;
                                  QUERY PLAN                                   
-------------------------------------------------------------------------------
 LockRows  (cost=0.00..129674.00 rows=5760000 width=20)
   Output: a.x, b.x, a.ctid, b.ctid
   ->  Nested Loop  (cost=0.00..72074.00 rows=5760000 width=20)
         Output: a.x, b.x, a.ctid, b.ctid
         ->  Seq Scan on public.a  (cost=0.00..34.00 rows=2400 width=10)
               Output: a.x, a.ctid
         ->  Materialize  (cost=0.00..46.00 rows=2400 width=10)
               Output: b.x, b.ctid
               ->  Seq Scan on public.b  (cost=0.00..34.00 rows=2400 width=10)
                     Output: b.x, b.ctid
(10 rows)

执行查询,然后将结果馈送到 LockRows 节点。锁行是做什么的?为此,是时候进行源代码潜水了。

< code > src/back end/executor/nodelockrows . c 中的< code > execclock rows 是相关代码。这里有很多,但它的要点是它在一个< code>RowMark列表上按顺序迭代,并按顺序获取每个锁。该列表由< code > exeinitlockrows 设置,它复制并过滤在计划期间准备并存储在< code>LockRows节点中的列表。

我没有时间在计划程序中回溯以查找LockRow创建的顺序,但IIRC基本上只是解析顺序(对于SELECT*)或字段在SELECT列表中出现的顺序(如果您没有使用*)。我建议不要依赖它。

 类似资料:
  • Introduction This is the sixth part of the chapter which describes synchronization primitives) in the Linux kernel and in the previous parts we finished to consider different readers-writer lock synch

  • 问题内容: SQL标准是否为多表查询指定锁定顺序? 例如,给定: SQL标准是保证锁定顺序还是由(特定于实现的)执行计划确定? 有没有办法保证锁定顺序? 如果没有办法保证锁定顺序,我们应该如何防止死锁? 更新 :在未解释您的推理之前,请不要投票结束该问题。就我而言,这是一个编程问题,这使Stackoverflow变得非常重要。如果您认为这个问题需要进一步完善,请解释一下,我们非常乐意为您解答。 问

  • 我看不出有什么区别。我读到了这篇文章:actual-use-of-lockinterruptbly-for-a-reentrantlock 想测试一下。代码如下: 这里是Inturrept班 控制台输出: 正如回答中提到的“这与常规锁()相同。但如果另一个线程中断,等待的线程lockInterruptbly()将抛出InterruptedException。”即使它是锁着的。lock()或lock

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

  • 我上面代码的日志是: 数据库也会更新。为什么lock()不工作?不是在lock()之后其他实例无法更新吗?还是别的什么?还是我错过了什么?

  • 问题内容: Goroutines在通道上的阻塞顺序是否决定了它们将解除阻塞的顺序?我不关心所发送消息的顺序(它们一定会被排序),但是不会影响Goroutines的顺序。 想象一下在多个Goroutine(1、2和3)之间共享一个空通道,每个Goroutine都尝试在上接收消息。由于为空,每个Goroutine将阻塞。当我向发送消息时,Goroutine 1将首先解锁吗?还是2或3可能会收到第一条消