Postgres何时以及如何使用“ transactionid”锁

问题描述 投票:1回答:1

我遇到了需要在9.6上解决这一问题,但有关9.6或更高版本的信息将不胜感激。

我的应用程序被数据库调用阻塞时遇到了问题,因为它试图获取另一个正在运行的事务的隐式transactionid锁。我不明白是为什么。

我了解每个交易在开始时都会根据其自身的交易ID(ExclusiveLock)获取一个pg_locks。没关系。在同一页面上,“通常”仅向“更改数据库状态”的事务分配一个永久ID。我在锁表中看到了永久ID,因此我认为发生了这种情况。但是,描述不够清晰,因为该页面既未指定“通常”是什么意思,也未指定“数据库状态更改”。]

但是我找不到任何指定语句何时尝试在其他事务上获取SharedLock的信息。 pg_locks中的唯一语句是:

[当进程发现有必要专门等待另一笔交易结束时,它会通过尝试获取另一笔交易的ID(取决于情况的虚拟ID或永久ID)的共享锁来做到这一点

这真的很模糊。无法请求事务锁定(至少我没有在Explicit Locking中看到它们)

所以我正在寻找以下答案:

  1. Postgres何时决定获取(共享的)另一个交易ID的transactionid锁?
  2. 究竟是什么导致Postgres为事务分配一个“永久ID”(这对我来说不重要如何解决数据库使用的问题,但是我普遍感到困惑,因为它在任何地方都缺乏确切的信息)
  3. 在这种特殊情况下,是什么使插入查询获得transactionid锁(也不太重要,因为如果有了引用,我就可以确定自己是我自己)

现在,由于特殊原因,在这种情况下我的查询被阻止:

相关pg_locks内容:

x=# select locktype,transactionid,virtualtransaction,pid,mode,granted
x-# from pg_locks where transactionid = '33682979' ;
   locktype    | transactionid | virtualtransaction |  pid   |     mode      | granted 
---------------+---------------+--------------------+--------+---------------+---------
 transactionid |      33682979 | 7/27909            | 476513 | ShareLock     | f
 transactionid |      33682979 | 5/387791           | 476509 | ExclusiveLock | t
(2 rows)

PID 476513被卡住,试图插入:

x=# SELECT wait_event_type, state, query 
x-# FROM pg_stat_activity 
x-# WHERE pid = 476513;
 wait_event_type | state  |                              query                                                                                                                     
-----------------+--------+--------------------------------------------------------------------
 Lock            | active | INSERT INTO association (id, device, campaign) VALUES ($1, $2, $3)
(1 row)

我启用了完整的语句日志记录,因此我还可以查看自声明上一个事务以来PID 476509的操作。我可以想象的唯一查询与此有关的事实是它已从association表中删除。

$ grep '476509.*execute' tx-lock.txt
<2020-06-17 13:58:37.743 CEST 476509.5/387791> LOG:  execute S_13: BEGIN
<2020-06-17 13:58:37.743 CEST 476509.5/387791> LOG:  execute <unnamed>: SELECT t0.* FROM campaign t0 WHERE t0.id = $1 FOR UPDATE
<2020-06-17 13:58:37.744 CEST 476509.5/387791> LOG:  execute <unnamed>: SELECT t0.* FROM campaign t0 WHERE t0.id = $1 FOR UPDATE
<2020-06-17 13:58:37.752 CEST 476509.5/387791> LOG:  execute <unnamed>: SELECT t0.* FROM association t0 WHERE (t0.enabled = $1 AND $2 = t0.campaign AND t0.statusCreated <> $3) LIMIT $4
<2020-06-17 13:58:37.759 CEST 476509.5/387791> LOG:  execute <unnamed>: DELETE FROM association WHERE id IN (SELECT DISTINCT t0.id FROM association t0 WHERE (t0.campaign = $1))
<2020-06-17 13:58:37.796 CEST 476509.5/387791> LOG:  execute <unnamed>: UPDATE campaign SET statusCreated = $1 WHERE id = $2
<2020-06-17 13:58:37.796 CEST 476509.5/387791> LOG:  execute S_42: SELECT t0.id FROM lock t0 WHERE t0.id = $1
<2020-06-17 13:58:37.796 CEST 476509.5/387791> LOG:  execute S_31: select id from lock where id = $1 for update
<2020-06-17 13:58:37.798 CEST 476509.5/387791> LOG:  execute <unnamed>: SELECT t0.*, t1.*id FROM groups t0 INNER JOIN devices t1 ON t0.device_id = t1.id AND t0.device_tenancy = t1.tenancy LEFT OUTER JOIN group_defs t2 ON t0.DEVICEGROUP_ID = t2.id WHERE ((t0.group_id = $1...) AND t1.tenancy = $36) ORDER BY t0.id ASC, t1.id ASC LIMIT $37

(请原谅一些查询,它们是由JPA创建的,而不是我创建的:))

postgresql postgresql-9.6 database-locking
1个回答
1
投票

通常表示事务正在等待它正在等待的事务所持有的行锁。

行锁不会永久存储在共享内存锁定表中,而是永久存储在xmax系统列中的表行中。存储的值是阻塞交易的交易号(通常)。

一旦交易发现谁持有该行的锁,它将开始等待该交易完成,这将释放它持有其自己的交易ID的排他锁。

© www.soinside.com 2019 - 2024. All rights reserved.