PostgreSQL咨询锁(advisory lock)

2023年 8月 15日 57.3k 0

一、什么是咨询锁?

PostgreSQL 支持创建咨询锁(advisory lock),该锁与数据库本身没有关系,其含义由应用来定义,咨询锁能够让 PostgreSQL 变成一个锁服务提供中心,为应用对一些非数据库资源并发访问提供控制。当然,也可以通过 select * from tb where id=xxx for update 来实现同样的功能,但是咨询锁因为与具体的数据没有关系,能够提供更好的性能。

PostgreSQL 咨询锁能够实现很多分布式系统中类似 Zookeeper 的锁服务,如在分布式系统中,多台服务器需要竞争,从而使自己成为 master,就可以通过竞争咨询锁来达成,谁得到咨询锁,谁就成为 master。

咨询锁支持会话级别和事务级别,会话级别的咨询锁,在会话结束时会自动释放,事务级别的咨询锁,在事务结束时自动释放。

二、咨询锁相关函数

咨询锁用一个 64 bit 的数字或者两个 32 bit 的数字来表示,并提供了一些函数来实现加锁和释放锁的操作,函数如下:

函数名称 返回类型 描述
pg_advisory_lock(key bigint) void session级别排他锁
pg_advisory_lock(key1 int, key2 int) void session级别排他锁
pg_advisory_lock_shared(key bigint) void session级别共享锁
pg_advisory_lock_shared(key1 int, key2 int) void session级别共享锁
pg_advisory_unlock(key bigint) boolean 释放session级别排他锁
pg_advisory_unlock(key1 int, key2 int) boolean 释放session级别排他锁
pg_advisory_unlock_all() void 释放本session持有的所有session级别的锁
pg_advisory_unlock_shared(key bigint) boolean 释放session级别共享锁
pg_advisory_unlock_shared(key1 int, key2 int) boolean 释放session级别共享锁
pg_advisory_xact_lock(key bigint) void 获取事务级别排他锁
pg_advisory_xact_lock(key1 int, key2 int) void 获取事务级别排他锁
pg_advisory_xact_lock_shared(key bigint) void 获取事务级别共享锁
pg_advisory_xact_lock_shared(key1 int, key2 int) void 获取事务级别共享锁
pg_try_advisory_lock(key bigint) boolean 试图获取session级别排他锁,成功返回true,否则返回false
pg_try_advisory_lock(key1 int, key2 int) boolean 试图获取session级别排他锁,成功返回true,否则返回false
pg_try_advisory_lock_shared(key bigint) boolean 试图获取session级别共享锁,成功返回true,否则返回false
pg_try_advisory_lock_shared(key1 int, key2 int) boolean 试图获取session级别共享锁,成功返回true,否则返回false
pg_try_advisory_xact_lock(key bigint) boolean 试图获取事务级别排他锁,成功返回true,否则返回false
pg_try_advisory_xact_lock(key1 int, key2 int) boolean 试图获取事务级别排他锁,成功返回true,否则返回false
pg_try_advisory_xact_lock_shared(key bigint) boolean 试图获取事务级别共享锁,成功返回true,否则返回false
pg_try_advisory_xact_lock_shared(key1 int, key2 int) boolean 试图获取事务级别共享锁,成功返回true,否则返回false

根据函数名称中的关键字,就能大概判断出函数的功能:

  • lock 为加锁。
  • unlock 释放锁。
  • xact 为事务级别的咨询锁,不包含 xact 为 session 级别的咨询锁。事务级别的咨询锁只有加锁函数,没有 unlock 函数,因为事务锁在事务结束后自动释放。
  • try 尝试加锁,不管是否能获得锁,都立即返回,不会一直等待。
  • 根据参数类型分为不同的函数,int 表示 32 位数字,bigint 表示 64 位数字。

三、咨询锁使用示例

以下展示了两个会话,获取 session 级排他咨询锁的示例:

session1:
pg=# select pg_advisory_lock(1); # session1 加锁
pg_advisory_lock
------------------
(1 row)

session2:
pg=# select pg_advisory_lock(1); # session2 阻塞

session1:
pg=# select pg_advisory_unlock(1); # session1 释放锁
pg_advisory_unlock
--------------------
t
(1 row)

session2:
pg=# select pg_advisory_lock(1); # session2 获得锁
pg_advisory_lock
------------------
(1 row)

四、咨询锁常见问题

  1. 当连接中断后,数据库的会话就会被中止,其持有的咨询锁也会被释放。
  2. 当事务提交或者回滚,持有的 session 级咨询锁不会被释放。
  3. 当一个 session 持有一把事务级的 key 值为 1 的锁,另外一个 session 不能持有 key 为 1 的 session 级的咨询锁。
  4. session 级别的排他锁,调用了几次 lock 函数,在释放时,也需要调用同样次数的 unlock 函数,才能真正释放。
  5. 在一个 64 位数字上加锁,永远不会阻塞两个 32 位数字上的锁,即使二者的数值一样,他们表示不同的空间。

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论