PostgreSQL 的 pg_advisory_lock 函数

PostgreSQL 的 pg_advisory_lock 函数

pg_advisory_lock 是 PostgreSQL 提供的一种应用级锁机制,它不锁定具体的数据库对象(如表或行),而是通过数字键值来协调应用间的并发控制。

锁的基本概念

PostgreSQL 提供两种咨询锁(advisory lock):

  1. 会话级咨询锁:锁在会话结束时自动释放
  2. 事务级咨询锁:锁在事务结束时自动释放

主要函数列表

函数描述
pg_advisory_lock(key)获取会话级咨询锁(阻塞)
pg_try_advisory_lock(key)尝试获取会话级咨询锁(非阻塞)
pg_advisory_xact_lock(key)获取事务级咨询锁(阻塞)
pg_try_advisory_xact_lock(key)尝试获取事务级咨询锁(非阻塞)
pg_advisory_unlock(key)释放会话级咨询锁
pg_advisory_unlock_all()释放当前会话持有的所有咨询锁

函数详解

1 pg_advisory_lock(key bigint)

功能:获取一个会话级别的咨询锁(如果锁已被其他会话持有,则阻塞等待)

参数

  • key:64位整数锁标识

示例

SELECT pg_advisory_lock(123456);
-- 执行需要同步的操作
SELECT pg_advisory_unlock(123456);

2 pg_try_advisory_lock(key bigint)

功能:尝试获取会话级咨询锁(非阻塞,立即返回成功与否)

返回值:boolean(true表示获取成功)

示例

DO $$
BEGINIF pg_try_advisory_lock(123456) THENRAISE NOTICE 'Lock acquired, performing work...';-- 执行受保护的操作PERFORM pg_advisory_unlock(123456);ELSERAISE NOTICE 'Could not acquire lock, skipping...';END IF;
END $$;

3 pg_advisory_xact_lock(key bigint)

功能:获取事务级咨询锁(锁在事务结束时自动释放)

示例

BEGIN;
SELECT pg_advisory_xact_lock(123456);
-- 执行需要同步的操作
COMMIT; -- 锁自动释放

4 pg_try_advisory_xact_lock(key bigint)

功能:尝试获取事务级咨询锁(非阻塞)

示例

BEGIN;
SELECT pg_try_advisory_xact_lock(123456);
-- 无论是否获取成功都继续执行
COMMIT;

锁的键值设计

咨询锁使用64位整数作为键值,有两种使用方式:

  1. 单键模式:使用一个64位整数

    SELECT pg_advisory_lock(123456789);
    
  2. 双键模式:使用两个32位整数组合

    SELECT pg_advisory_lock(123, 456);
    

实际应用场景

场景1:防止定时任务重复执行

-- 在定时任务开始时检查锁
DO $$
BEGINIF NOT pg_try_advisory_xact_lock(987654) THENRAISE NOTICE 'Task is already running in another process';RETURN;END IF;RAISE NOTICE 'Starting scheduled task...';-- 执行定时任务逻辑-- ...COMMIT; -- 锁自动释放
END $$;

场景2:应用级分布式锁

-- 应用1获取锁
SELECT pg_advisory_lock(555555) FROM my_table WHERE id = 1;-- 应用2尝试获取同样的锁
SELECT pg_try_advisory_lock(555555); -- 返回false-- 应用1释放锁
SELECT pg_advisory_unlock(555555);

场景3:确保单实例初始化

-- 系统初始化时确保只执行一次
DO $$
BEGIN-- 尝试获取锁,等待最多5秒FOR i IN 1..5 LOOPIF pg_try_advisory_lock(1357924680) THEN-- 检查是否已经初始化IF NOT EXISTS (SELECT 1 FROM system_status WHERE initialized = true) THEN-- 执行初始化INSERT INTO system_status(initialized) VALUES (true);RAISE NOTICE 'System initialized successfully';ELSERAISE NOTICE 'System already initialized';END IF;-- 显式释放锁(虽然会话结束会自动释放)PERFORM pg_advisory_unlock(1357924680);RETURN;END IF;PERFORM pg_sleep(1); -- 等待1秒END LOOP;RAISE EXCEPTION 'Could not acquire initialization lock after 5 seconds';
END $$;

监控咨询锁

查看当前持有的咨询锁

SELECT locktype, classid, objid, objsubid, mode, granted
FROM pg_locks
WHERE locktype = 'advisory';

查看所有咨询锁(包括已授予和等待的)

SELECT pid, locktype, mode, granted, fastpath, virtualtransaction
FROM pg_locks 
WHERE locktype = 'advisory';

注意事项

  1. 锁释放

    • 会话级锁必须显式释放或会话结束自动释放
    • 事务级锁在事务结束时自动释放
  2. 死锁风险

    • 按固定顺序获取多个咨询锁以避免死锁
    • 使用 pg_try_advisory_lock 可以降低死锁风险
  3. 性能影响

    • 咨询锁比表锁/行锁更轻量级
    • 大量使用仍可能影响性能
  4. 集群环境

    • 咨询锁只在单个PostgreSQL实例内有效
    • 不适用于跨多个数据库实例的协调
  5. 锁标识管理

    • 建议在应用中集中管理锁标识
    • 使用有意义的常量而非魔法数字

高级用法

超时获取锁

DO $$
DECLARElock_acquired BOOLEAN := false;timeout INTERVAL := '5 seconds';start_time TIMESTAMP := clock_timestamp();
BEGINWHILE (clock_timestamp() - start_time) < timeout LOOPIF pg_try_advisory_lock(424242) THENlock_acquired := true;EXIT;END IF;PERFORM pg_sleep(0.1); -- 等待100msEND LOOP;IF lock_acquired THENRAISE NOTICE 'Lock acquired after %', clock_timestamp() - start_time;-- 执行受保护的操作PERFORM pg_advisory_unlock(424242);ELSERAISE EXCEPTION 'Could not acquire lock within timeout';END IF;
END $$;

使用咨询锁实现队列

-- 生产者
SELECT pg_advisory_lock(987); -- 全局写锁-- 插入队列项
INSERT INTO job_queue(job_data) VALUES ('some data');SELECT pg_advisory_unlock(987);-- 消费者
SELECT pg_advisory_lock(988); -- 全局读锁-- 获取并锁定一个作业
UPDATE job_queue 
SET status = 'processing', worker_id = pg_backend_pid(),claimed_at = NOW()
WHERE id = (SELECT id FROM job_queue WHERE status = 'pending' ORDER BY created_at LIMIT 1
)
RETURNING *;SELECT pg_advisory_unlock(988);

pg_advisory_lock 是 PostgreSQL 强大的应用级同步机制,合理使用可以解决复杂的并发控制问题,但需要谨慎设计以避免死锁和性能问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/80064.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SGLang 实战介绍 (张量并行 / Qwen3 30B MoE 架构部署)

一、技术背景 随着大语言模型&#xff08;LLM&#xff09;的飞速发展&#xff0c;如何更高效、更灵活地驾驭这些强大的模型生成我们期望的内容&#xff0c;成为了开发者们面临的重要课题。传统的通过拼接字符串、管理复杂的状态和调用 API 的方式&#xff0c;在处理复杂任务时…

微服务中 本地启动 springboot 无法找到nacos配置 启动报错

1. 此处的环境变量需要匹配nacos中yml配置文件名的后缀 对于粗心的小伙伴在切换【测试】【开发】环境的nacos使用时会因为这里导致项目总是无法启动成功

Lua从字符串动态构建函数

在 Lua 中&#xff0c;你可以通过 load 或 loadstring&#xff08;Lua 5.1&#xff09;函数从字符串动态构建函数。以下是一个示例&#xff1a; 示例 1&#xff1a;基本动态函数构建 -- 动态构建一个函数 local funcStr "return function(a, b) return a b end"-…

【Python】‌Python单元测试框架unittest总结

1. 本期主题&#xff1a;Python单元测试框架unittest详解 unittest是Python内置的单元测试框架&#xff0c;遵循Java JUnit的"测试驱动开发"&#xff08;TDD&#xff09;理念&#xff0c;通过继承TestCase类实现测试用例的模块化组织。本文聚焦于独立测试脚本的编写…

【Python 实战】---- 使用Python批量将 .ncm 格式的音频文件转换为 .mp3 格式

1. 前言 .ncm 格式是网易云音乐专属的加密音频格式,用于保护版权。这种格式无法直接播放,需要解密后才能转换为常见的音频格式。本文将介绍如何使用 Python 批量将 .ncm 格式的音频文件转换为 .mp3 格式。 2. 安装 ncmdump ncmdump 是一个专门用于解密 .ncm 文件的工具。它…

Linux 学习笔记2

Linux 学习笔记2 一、定时任务调度操作流程注意事项 二、磁盘分区与管理添加新硬盘流程磁盘管理命令 三、进程管理进程操作命令服务管理&#xff08;Ubuntu&#xff09; 四、注意事项 一、定时任务调度 操作流程 创建脚本 vim /path/to/script.sh # 编写脚本内容设置可执行权…

YOLO目标检测算法

文章目录 前言一、目标检测算法简介1、传统目标检测算法&#xff08;1&#xff09;R-CNN算法简介&#xff08;2&#xff09;Fast R-CNN算法简介&#xff08;3&#xff09;Faster R-CNN算法简介 2、目标检测中的算法设计范式&#xff08;1&#xff09;one-stage&#xff08;2&am…

【软件设计师:软件】20.软件设计概述

一、软件设计基本原则 一、软件设计基本原则 1. 模块 是指执行某一特定任务的数据结构和程序代码。 将模块的接口和功能定义为其外部特性将模块的局部数据和实现该模块的程序代码称为内部特性。在模块设计时,最重要的原则就是实现信息隐蔽和模块独立。 2 . 信息隐蔽 将每…

软件工程之面向对象分析深度解析

前文基础&#xff1a; 1.软件工程学概述&#xff1a;软件工程学概述-CSDN博客 2.软件过程深度解析&#xff1a;软件过程深度解析-CSDN博客 3.软件工程之需求分析涉及的图与工具&#xff1a;软件工程之需求分析涉及的图与工具-CSDN博客 4.软件工程之形式化说明技术深度解…

需求分析阶段测试工程师主要做哪些事情

在软件测试需求分析阶段&#xff0c;主要围绕确定测试范围、明确测试目标、细化测试内容等方面开展工作&#xff0c;为后续测试计划的制定、测试用例的设计以及测试执行提供清晰、准确的依据。以下是该阶段具体要做的事情&#xff1a; 1. 需求收集与整理 收集需求文档&#x…

vLLM部署Qwen2-7B模型推理

vllm简介 vLLM是一个高效的大语言模型推理和部署服务系统&#xff0c;专为大型语言模型的高效执行而设计。它不仅支持多种量化技术以减少模型大小和加速推理过程&#xff0c;还提供了与OpenAI API兼容的服务接口&#xff0c;使得现有的应用程序能够无缝对接。 一、前提环境 …

【STM32 学习笔记】GPIO输入与输出

GPIO详解 一、GPIO基本概念 GPIO&#xff08;通用输入输出&#xff09;是微控制器与外部设备交互的核心接口&#xff0c;具有以下特性&#xff1a; 可编程控制输入/输出模式支持数字信号的读取与输出集成多种保护机制复用功能支持片上外设连接 二、GPIO位结构解析 2.1 保护二…

安科瑞光伏综自系统在新能源电站中的应用及调度上传方案研究

摘要 随着全球对清洁能源需求的不断增长&#xff0c;光伏发电作为一种可持续的能源解决方案&#xff0c;正迅速发展。光伏综合自动化系统&#xff08;综自系统&#xff09;在确保光伏电站高效、稳定运行方面起着关键作用。本文详细介绍了安科瑞光伏综自系统&#xff0c;包括其背…

[python] 函数2-匿名函数

一 匿名函数 格式: 函数名 lambda 形参 : 返回值(表达式) 调用: 结果 函数名(实参) 一般只有一行代码,他是对def定义函数的一种简化,只能实现简单的逻辑 逻辑复杂时不要使用lambda add lambda a,b: ab # a,b就是形参 print(add(2,5)) 1.1 无参数 noargs_func lambda…

深入理解C/C++内存管理:从基础到高级优化实践

一、内存区域划分与基础管理机制​​ ​​栈&#xff08;Stack&#xff09;​​ 栈由系统自动管理&#xff0c;用于存储函数调用时的局部变量、参数及返回地址。其特点是高效但空间有限&#xff08;通常1-8MB&#xff09;&#xff0c;遵循后进先出&#xff08;LIFO&#xff09;…

kafka 面试总结

Kafka的幂等性是一种机制&#xff0c;确保生产者发送的每条消息在Broker端只被持久化一次&#xff0c;即使生产者因网络问题等原因重试发送&#xff0c;也不会导致消息重复。 实现原理 生产者ID&#xff08;PID&#xff09; 每个生产者实例在初始化时&#xff0c;会被分配一个…

uniapp|实现多终端聊天对话组件、表情选择、消息发送

基于UniApp框架,实现跨平台多终端适配的聊天对话组件开发、表情选择交互设计及消息发送,支持文本与表情混合渲染。 目录 聊天界面静态组件实现消息列表布局消息气泡双向布局辅助元素定位与样式静态数据模拟与扩展性设计表情选择器静态模块浮层实现符号网格排列多端样式适配方…

LabVIEW超声波液位计检定

在工业生产、运输和存储等环节&#xff0c;液位计的应用十分广泛&#xff0c;其中超声波液位计作为非接触式液位测量设备备受青睐。然而&#xff0c;传统立式水槽式液位计检定装置存在受建筑高度影响、量程范围受限、流程耗时长等问题&#xff0c;无法满足大量程超声波液位计的…

C++漫步结构与平衡的殿堂:AVL树

文章目录 1.AVL树的概念2.AVL树的结构3.AVL树的插入4.AVL树的旋转4.1 左单旋4.2 右单旋4.3 右左双旋4.4 左右双旋 5.AVL树的删除6.AVL树的高度7.AVL树的平衡判断希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力&#xff01; 二叉搜索树有其自身的缺陷&#xf…

Verilog Test Fixture 时钟激励

1、占空比50%时钟产生 always begin<clock> 1b0 ;#<PERIOD/2> ;<clock> 1b1 ;#<PERIOD/2> ; end reg <clock> 1b0 ;alwaysbegin#<PERIOD/2> ;<clock> ~<clock> ;end 2…