我遇到了需要在9.6上解决这一问题,但有关9.6或更高版本的信息将不胜感激。
我的应用程序被数据库调用阻塞时遇到了问题,因为它试图获取另一个正在运行的事务的隐式transactionid
锁。我不明白是为什么。
我了解每个交易在开始时都会根据其自身的交易ID(ExclusiveLock
)获取一个pg_locks。没关系。在同一页面上,“通常”仅向“更改数据库状态”的事务分配一个永久ID。我在锁表中看到了永久ID,因此我认为发生了这种情况。但是,描述不够清晰,因为该页面既未指定“通常”是什么意思,也未指定“数据库状态更改”。]
但是我找不到任何指定语句何时尝试在其他事务上获取SharedLock
的信息。 pg_locks中的唯一语句是:
[当进程发现有必要专门等待另一笔交易结束时,它会通过尝试获取另一笔交易的ID(取决于情况的虚拟ID或永久ID)的共享锁来做到这一点
这真的很模糊。无法请求事务锁定(至少我没有在Explicit Locking中看到它们)
所以我正在寻找以下答案:
transactionid
锁?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创建的,而不是我创建的:))
通常表示事务正在等待它正在等待的事务所持有的行锁。
行锁不会永久存储在共享内存锁定表中,而是永久存储在xmax
系统列中的表行中。存储的值是阻塞交易的交易号(通常)。
一旦交易发现谁持有该行的锁,它将开始等待该交易完成,这将释放它持有其自己的交易ID的排他锁。