如何使用字符串作为PostgreSQL建议锁的密钥?

时间:2015-03-30 18:47:07

标签: postgresql hash locking

PostgreSQL中有一个名为advisory locking的锁定机制。它提供以下API functions

允许我们获取此类锁的函数接受一个大整数参数:pg_advisory_lock(key bigint)或两个整数键:pg_advisory_lock(key1 int, key2 int)(第二种形式)。

我可以使用什么抽象机制来使用字符串键而不是整数键?也许一些哈希功能可以完成这项工作?

是否可以仅在PostgreSQL中实现它,而无需在应用程序级别将字符串转换为整数?

如果难以实现预期目标,我可以使用两个整数来标识表中的行。第二个整数可以是行的主键,但是我可以使用什么整数作为表标识符?

1 个答案:

答案 0 :(得分:17)

您已经找到了最有可能的候选人:使用表的合成主键加上表标识符作为键。

您可以使用pg_class中的表格oid(对象标识符)来指定表格。伪类型regclass的便利性为您查找,或者您可以select c.oid from pg_class c inner join pg_namespace n where n.nspname = 'public' and c.relname = 'mytable'按模式获取它。

存在一个小问题,因为oid内部是无符号的32位整数,但{arg形式的pg_advisory_lock采用带符号的整数。这在实践中不太可能是一个问题,因为在出​​现这个问题之前,你需要经过批次的OID。

e.g。

SELECT pg_advisory_lock('mytable'::regclass::integer, 42);

但是,如果你要这样做,你基本上是使用咨询锁来模拟行锁定。那么为什么不使用行锁?

SELECT 1
FROM mytable
WHERE id = 42
FOR UPDATE OF mytable;

现在,如果你真的不得不使用字符串键,那么你将不得不接受会发生冲突,因为你将使用相当小的哈希值。

PostgreSQL具有内置的散列函数,用于散列连接。它们不是加密哈希 - 它们被设计得很快并且产生相当小的结果。这就是你为此目的所需要的。

他们实际上哈希到int4,你真的更喜欢int8,所以你的碰撞风险更高。另一种方法是采用像md5这样的慢速加密哈希并截断它,这只是丑陋。

所以,如果你真的觉得你必须这样做,你可以这样做:

select pg_advisory_lock( hashtext('fredfred') );

...但是,只有当您的应用程序能够应对其他字符串不可避免地产生相同哈希的事实时,您才会看到一行“锁定”并未真正锁定。