← 返回题目列表

PostgreSQL Advisory Lock 是什么?和行锁有什么区别?

高频 中等 第 15 / 31 题 更新于 2026/07/29
PostgreSQLAdvisory Lock分布式锁并发控制

简化版

Advisory Lock 是 PostgreSQL 提供的应用级协作锁,锁的是一个业务自定义的数字 key,而不是某一行数据。它适合任务互斥、定时任务防重、业务资源串行化;但数据库不会理解这个 key 的业务含义,必须由应用统一约定并保证释放。

详细版

行锁依附于表行,updateselect for update 会锁住真实数据行。Advisory Lock 不依附具体行,而是通过 pg_advisory_lockpg_try_advisory_lock 等函数锁住一个整数 key。

特点:

  • 可以做事务级锁或会话级锁。
  • 适合没有天然数据行可锁的业务资源。
  • try 版本能非阻塞尝试获取。
  • key 设计要避免冲突。
  • 会话级锁要防连接池导致未释放。

它不是自动业务约束,所有参与方必须遵守同一套加锁规则。

完整版教学

一、Advisory Lock 是应用约定的锁

普通行锁锁的是数据库知道的行。Advisory Lock 锁的是应用传入的数字 key,数据库只负责互斥,不知道这个 key 代表订单、用户还是任务。

select pg_try_advisory_lock(1001);

如果所有应用都约定 1001 表示某个业务资源,那么这个锁就能实现互斥。如果有代码不遵守约定,直接绕过锁操作数据,数据库不会阻止它。

记忆钩子:Advisory Lock 是“君子协定锁”,数据库管互斥,业务管含义。

二、它和行锁的区别

行锁依赖真实行,适合保护某条记录。Advisory Lock 不需要有对应行,适合保护抽象资源。

对比行锁Advisory Lock
锁对象表中的行自定义 key
数据库是否理解业务理解行关系不理解业务含义
典型场景更新账户、订单定时任务、资源互斥
绕过风险SQL 更新会遇到锁不加锁的代码可绕过

如果资源本身就是一行数据,优先考虑行锁或条件更新;如果资源没有天然行,Advisory Lock 更方便。

三、事务级锁和会话级锁要分清

PostgreSQL Advisory Lock 有事务级和会话级两类。事务级锁会在事务结束时自动释放;会话级锁要显式释放或连接断开才释放。

-- 事务级
select pg_advisory_xact_lock(1001);

-- 会话级
select pg_advisory_lock(1001);
select pg_advisory_unlock(1001);

Web 应用里更推荐事务级锁,因为连接池复用连接时,会话级锁如果忘记释放,可能影响后续请求。

四、try lock 适合防重复任务

pg_try_advisory_lockpg_try_advisory_xact_lock 会立即返回是否获取成功,不会一直等待。这适合定时任务防重复。

select pg_try_advisory_xact_lock(20260729);

如果返回 false,说明别的实例正在执行,当前实例可以直接跳过。这样多个应用实例部署同一个定时任务时,只会有一个真正执行。

五、key 设计要稳定且避免冲突

Advisory Lock 的 key 是数字,可以用一个 bigint,也可以用两个 int。业务上要把资源映射成稳定 key。

任务锁: hash('daily_report')
用户锁: user_id
订单锁: order_id
租户任务锁: tenant_id + job_type

如果 key 设计冲突,不相关资源会互相阻塞;如果 key 不统一,同一个资源又可能被多个 key 表示,锁就失效。

六、它不替代唯一约束和事务

Advisory Lock 可以减少并发冲突,但不能替代数据库约束。比如防止重复订单,仍应有唯一索引或幂等表兜底。

Advisory Lock: 减少同一资源并发执行
唯一索引: 防止重复数据最终落库
事务: 保证一组数据修改原子性

面试中要避免把 Advisory Lock 说成万能分布式锁。它是 PostgreSQL 内部锁,适用于使用同一个数据库作为协调点的场景。

七、常见误区与追问

  • 误区:Advisory Lock 会自动保护某张表。 它只保护自定义 key,必须应用代码共同遵守。
  • 误区:会话级锁用起来更安全。 连接池下忘记释放会污染连接,Web 请求更推荐事务级锁。
  • 误区:有 Advisory Lock 就不用唯一索引。 唯一性仍要靠数据库约束兜底。
  • 追问:try lock 有什么用? 非阻塞尝试获取锁,适合任务防重和快速失败。
  • 追问:key 冲突会怎样? 不相关业务会互相阻塞,导致性能和可用性问题。
  • 追问:它能跨服务使用吗? 可以,只要服务连接同一个 PostgreSQL 集群并遵守同一 key 规则。

八、面试中可以这样落地

多个实例执行同一个日报任务,可以用事务级 try lock:

begin;
select pg_try_advisory_xact_lock(900001);
-- true 才执行任务核心逻辑
commit;

如果获取失败就跳过本次执行。任务产生的数据仍要有唯一约束,例如 (report_date, tenant_id),防止异常情况下重复写入。

九、加强记忆

Advisory Lock 记住“自定义 key、应用约定、事务级优先、约束兜底”。它适合任务互斥和抽象资源串行化,但数据库不知道业务含义。面试回答时一定要补上连接池释放风险和唯一索引兜底。