如何使用字符串作为 PostgreSQL 咨询锁的键?
How do I use string as a key to PostgreSQL advisory lock?
PostgreSQL 中有一种锁定机制,称为 advisory locking. It provides the following API functions。
允许我们获得这种锁的函数接受一个大整数参数:pg_advisory_lock(key bigint)
或两个整数键:pg_advisory_lock(key1 int, key2 int)
(第二种形式)。
我可以使用什么抽象机制来使用字符串键而不是整数键?也许一些散列函数可以完成这项工作?
是否可以仅在 PostgreSQL 中实现此功能而无需在应用程序级别将字符串转换为整数?
如果难以实现预期的目标,也许我可以使用两个整数来标识 table 中的行。第二个整数可以是行的主键,但是我可以使用什么整数作为 table 标识符?
您已经找到了最有可能的候选者:使用 table 加上 table 标识符的合成主键作为键。
您可以使用 pg_class
中 table 的 oid(对象标识符)来指定 table。转换为伪类型 regclass
的便利为您查找,或者您可以 select c.oid from pg_class c inner join pg_namespace n where n.nspname = 'public' and c.relname = 'mytable'
按模式获取它。
有一个小问题,因为 oid
在内部是一个无符号的 32 位整数,但是 pg_advisory_lock
的双参数形式采用 有符号 整数。这在实践中不太可能成为问题,因为在这成为问题之前您需要检查 很多 个 OID。
例如
SELECT pg_advisory_lock('mytable'::regclass::integer, 42);
但是,如果您要这样做,您基本上是在使用咨询锁模拟行锁定。那么为什么不直接使用行锁定呢?
SELECT 1
FROM mytable
WHERE id = 42
FOR UPDATE OF mytable;
现在,如果您真的必须使用字符串键,您将不得不接受会发生冲突,因为您将使用相当小的散列。
PostgreSQL 具有用于哈希连接的内置哈希函数。它们不是加密散列——它们被设计为速度很快并且产生的结果相当小。这就是您为此目的所需要的。
它们实际上散列为 int4,而您确实更喜欢 int8,因此 运行 发生冲突的风险更高。不过,另一种方法是采用像 md5 和 t运行cate 这样的慢速加密散列,但这很丑陋。
所以如果你真的、真的觉得你必须这么做,你可以这样做:
select pg_advisory_lock( hashtext('fredfred') );
...但前提是您的应用程序能够处理这样一个事实,即其他字符串可以生成相同的散列是不可避免的table,因此您可能会看到一行 "locked" 即没有真正锁定。
PostgreSQL 中有一种锁定机制,称为 advisory locking. It provides the following API functions。
允许我们获得这种锁的函数接受一个大整数参数:pg_advisory_lock(key bigint)
或两个整数键:pg_advisory_lock(key1 int, key2 int)
(第二种形式)。
我可以使用什么抽象机制来使用字符串键而不是整数键?也许一些散列函数可以完成这项工作?
是否可以仅在 PostgreSQL 中实现此功能而无需在应用程序级别将字符串转换为整数?
如果难以实现预期的目标,也许我可以使用两个整数来标识 table 中的行。第二个整数可以是行的主键,但是我可以使用什么整数作为 table 标识符?
您已经找到了最有可能的候选者:使用 table 加上 table 标识符的合成主键作为键。
您可以使用 pg_class
中 table 的 oid(对象标识符)来指定 table。转换为伪类型 regclass
的便利为您查找,或者您可以 select c.oid from pg_class c inner join pg_namespace n where n.nspname = 'public' and c.relname = 'mytable'
按模式获取它。
有一个小问题,因为 oid
在内部是一个无符号的 32 位整数,但是 pg_advisory_lock
的双参数形式采用 有符号 整数。这在实践中不太可能成为问题,因为在这成为问题之前您需要检查 很多 个 OID。
例如
SELECT pg_advisory_lock('mytable'::regclass::integer, 42);
但是,如果您要这样做,您基本上是在使用咨询锁模拟行锁定。那么为什么不直接使用行锁定呢?
SELECT 1
FROM mytable
WHERE id = 42
FOR UPDATE OF mytable;
现在,如果您真的必须使用字符串键,您将不得不接受会发生冲突,因为您将使用相当小的散列。
PostgreSQL 具有用于哈希连接的内置哈希函数。它们不是加密散列——它们被设计为速度很快并且产生的结果相当小。这就是您为此目的所需要的。
它们实际上散列为 int4,而您确实更喜欢 int8,因此 运行 发生冲突的风险更高。不过,另一种方法是采用像 md5 和 t运行cate 这样的慢速加密散列,但这很丑陋。
所以如果你真的、真的觉得你必须这么做,你可以这样做:
select pg_advisory_lock( hashtext('fredfred') );
...但前提是您的应用程序能够处理这样一个事实,即其他字符串可以生成相同的散列是不可避免的table,因此您可能会看到一行 "locked" 即没有真正锁定。