一尘不染

提交事务时以原子方式设置SERIAL值

sql

假设我有一个表,我想在其中使用serial主键从客户端请求更改。客户会问:“给我X键后的更改”。如果不使用SERIALIZABLE隔离级别或锁定,则很容易出现竞争状况。

事务A可以先开始,然后进行写操作,然后花很长时间提交。同时,事务B将在A提交之前启动并提交。来自B的写操作将获得比来自A的写操作更高的主键。如果客户端现在请求更改,它将错过仍未提交的来自A的写操作,并记下最新的最高主键。因此,即使在提交A之后,客户端也永远不会看到该更改,因为它的密钥低于客户端已经获得的更改。

是否可以serial在提交时自动确定a
(或与计数器相似的值)的值,以便我们保证在提交时它的值将高于所有其他值,而在提交后将比所有其他值都低?如果不是,解决此问题的最佳方法是什么?


阅读 129

收藏
2021-03-17

共1个答案

一尘不染

Postgres 9.5 引入了与此问题相关的新功能: commit timestamps

你只需要激活track_commit_timestamppostgresql.conf(并重新启动!)开始跟踪提交时间戳。然后您可以查询:

SELECT * FROM tbl
WHERE  pg_xact_commit_timestamp(xmin) >= '2015-11-26 18:00:00+01';

阅读Postgres
Wiki中的“提交时间戳跟踪”一章。手册中的
相关实用程序功能

函数波动性仅VOLATILE是因为事务ID(xid)可以围绕每个定义进行包装。因此,您 无法 在其上 创建功能索引
您可以IMMUTABLE在有限的时间内为应用程序伪装函数包装中的易变性,但是您需要注意其含义。

对于许多只关注提交顺序(而不是绝对时间)的用例(例如您的?),使用xmin强制转换为bigint“直接”(xmin::text::bigint)而不是提交时间戳可能更有效。(xid内部是一个无符号整数,上半部分不适合有符号integer。)同样,请注意由于可能的xid环绕而造成的限制。

出于同样的原因,提交时间戳记 不会无限期保留 。对于中小型数据库,xid几乎不会发生环绕操作-
但是,如果群集的生存时间足够长,则最终会发生环绕操作。有关详细信息,请阅读手册中的“防止事务ID环绕失败”一章。

2021-03-17