PostgreSQL 的 pg_advisory_lock_shared 函数

PostgreSQL 的 pg_advisory_lock_shared 函数详解

pg_advisory_lock_shared 是 PostgreSQL 提供的共享咨询锁函数,允许多个会话同时获取相同键值的共享锁,但排斥排他锁。

共享咨询锁 vs 排他咨询锁

锁类型共享锁 (pg_advisory_lock_shared)排他锁 (pg_advisory_lock)
并发性允许多个会话同时持有同一时间只能由一个会话持有
排斥性排斥排他锁排斥共享锁和排他锁
使用场景读多写少场景独占访问场景

共享咨询锁函数家族

PostgreSQL 提供以下共享咨询锁相关函数:

函数描述锁类型
pg_advisory_lock_shared(key)获取共享会话级咨询锁(阻塞)共享锁
pg_try_advisory_lock_shared(key)尝试获取共享会话级咨询锁(非阻塞)共享锁
pg_advisory_xact_lock_shared(key)获取共享事务级咨询锁(阻塞)共享锁
pg_try_advisory_xact_lock_shared(key)尝试获取共享事务级咨询锁(非阻塞)共享锁
pg_advisory_unlock_shared(key)释放共享会话级咨询锁-

函数详解

1 pg_advisory _lock_shared(key bigint)

功能:获取会话级共享咨询锁(阻塞)

参数

  • key :64位整数锁标识

示例

-- 会话1获取共享锁
SELECT pg_advisory_lock_shared(123456);-- 会话2可以同时获取相同的共享锁
SELECT pg_advisory_lock_shared(123456);-- 但会话3尝试获取排他锁会被阻塞
SELECT pg_advisory_lock(123456); -- 阻塞直到共享锁释放

2 pg_try_advisory_lock_shared(key bigint)

功能:尝试获取共享会话级咨询锁(非阻塞)

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

示例

DO $$
BEGINIF pg_try_advisory_lock_shared(123456) THENRAISE NOTICE 'Shared lock acquired, performing read operations...';-- 执行只读操作PERFORM pg_advisory_unlock_shared(123456);ELSERAISE NOTICE 'Could not acquire shared lock';END IF;
END $$;

3 pg_advisory_xact_lock_shared(key bigint)

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

示例

BEGIN;
SELECT pg_advisory_xact_lock_shared(123456);
-- 执行只读操作
COMMIT; -- 锁自动释放

锁兼容性矩阵

当前持有锁 \ 请求锁共享锁排他锁
无锁允许允许
共享锁允许阻塞
排他锁阻塞阻塞

实际应用场景

场景1:读写分离控制

-- 读操作使用共享锁
DO $$
BEGINPERFORM pg_advisory_lock_shared(555);-- 多个会话可以同时执行读操作RAISE NOTICE 'Reading data: %', (SELECT count(*) FROM large_table);PERFORM pg_advisory_unlock_shared(555);
EXCEPTION WHEN OTHERS THENPERFORM pg_advisory_unlock_shared(555);RAISE;
END $$;-- 写操作使用排他锁
DO $$
BEGINPERFORM pg_advisory_lock(555); -- 会阻塞直到所有共享锁释放-- 独占执行写操作INSERT INTO large_table VALUES (...);PERFORM pg_advisory_unlock(555);
EXCEPTION WHEN OTHERS THENPERFORM pg_advisory_unlock(555);RAISE;
END $$;

场景2:缓存更新控制

-- 缓存读取(多个客户端可同时读取)
CREATE OR REPLACE FUNCTION get_cached_data(cache_key text) RETURNS json AS $$
DECLAREresult json;
BEGIN-- 获取共享锁(允许并发读取)PERFORM pg_advisory_lock_shared(hashtext(cache_key));SELECT data INTO result FROM cache_table WHERE key = cache_key;PERFORM pg_advisory_unlock_shared(hashtext(cache_key));RETURN result;
END;
$$ LANGUAGE plpgsql;-- 缓存更新(独占访问)
CREATE OR REPLACE FUNCTION update_cache(cache_key text, new_data json) RETURNS void AS $$
BEGIN-- 获取排他锁(阻塞直到所有共享锁释放)PERFORM pg_advisory_lock(hashtext(cache_key));-- 执行更新INSERT INTO cache_table(key, data, updated_at)VALUES (cache_key, new_data, NOW())ON CONFLICT (key) DO UPDATESET data = EXCLUDED.data, updated_at = NOW();PERFORM pg_advisory_unlock(hashtext(cache_key));
END;
$$ LANGUAGE plpgsql;

场景3:配置热加载

-- 配置读取(多个服务实例可同时读取)
CREATE OR REPLACE FUNCTION get_config() RETURNS SETOF config_entry AS $$
BEGIN-- 获取共享锁确保配置加载过程中不被修改PERFORM pg_advisory_lock_shared(1); -- 使用固定键值1表示配置锁RETURN QUERY SELECT * FROM application_config;PERFORM pg_advisory_unlock_shared(1);
END;
$$ LANGUAGE plpgsql;-- 配置更新(管理员调用)
CREATE OR REPLACE FUNCTION reload_config(new_config json) RETURNS void AS $$
BEGIN-- 获取排他锁确保没有服务正在读取配置PERFORM pg_advisory_lock(1);-- 清空并重新加载配置TRUNCATE application_config;INSERT INTO application_configSELECT * FROM json_populate_recordset(NULL::config_entry, new_config);PERFORM pg_advisory_unlock(1);
END;
$$ LANGUAGE plpgsql;

监控共享咨询锁

查看当前共享锁

SELECT pid, locktype, mode, granted 
FROM pg_locks 
WHERE locktype = 'advisory' AND mode LIKE '%Share%';

查看锁等待情况

SELECT blocked.pid AS blocked_pid,blocking.pid AS blocking_pid,blocked.query AS blocked_query,blocking.query AS blocking_query,blocked.mode AS blocked_mode,blocking.mode AS blocking_mode
FROM pg_catalog.pg_locks blocked
JOIN pg_catalog.pg_stat_activity blocking ON blocking.pid = blocked.blocking_pid
WHERE blocked.locktype = 'advisory' AND NOT blocked.granted;

注意事项

  1. 锁释放

    • 必须确保每个 pg_advisory_lock_shared() 调用都有对应的 pg_advisory_unlock_shared()
    • 事务级共享锁会在事务结束时自动释放
  2. 死锁风险

    • 共享锁之间不会死锁
    • 但共享锁与排他锁混合使用时可能产生死锁
    • 建议使用固定的锁获取顺序
  3. 性能考虑

    • 共享锁比排他锁允许更高的并发性
    • 但大量共享锁仍可能影响性能
  4. 锁粒度

    • 使用不同键值控制不同资源的访问
    • 避免使用太少键值导致过度争用
  5. 会话管理

    • 确保异常情况下锁能被释放(使用EXCEPTION块)
    • 长时间持有锁可能导致其他会话长时间等待

pg_advisory_lock_shared 是实现读多写少场景并发控制的强大工具,合理使用可以显著提高系统吞吐量,特别是在需要协调多个读取者与少量写入者的场景中。

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

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

相关文章

Halcon之计算抓取螺母的位姿

文章目录 1,项目说明。2,注意事项3,关联的主要算子3.1, gen_parallels_xld 3.2 ,convert_pose_type 4,程序流程。5,代码6,Demo链接。 1,项目说明。 Robot标定使用的模式…

互联网大厂Java求职面试:AI集成场景下的技术挑战与架构设计

标题:互联网大厂Java求职面试:AI集成场景下的技术挑战与架构设计 第一幕:向量数据库选型与性能调优 技术总监(严肃脸): 郑薪苦,我们最近在做一个基于大语言模型的企业级AI应用,需要…

ABB电机控制和保护单元与Profibus DP主站转Modbus TCP网关快速通讯案例

ABB电机控制和保护单元与Profibus DP主站转Modbus TCP网关快速通讯案例 在现代工业自动化系统中,设备之间的互联互通至关重要。Profibus DP和Modbus TCP是两种常见的通信协议,分别应用于不同的场景。为了实现这两种协议的相互转换,Profibus …

智慧农业、智慧养殖平台—监控摄像头管理监控设计—仙盟创梦IDE

智慧养殖 监控摄像头是核心管理工具,主要通过以下方式提升养殖效率与管理水平: 环境实时监测:对养殖区域进行全天候可视化监控,及时捕捉温度、湿度、通风等环境要素变化,确保动物生存环境稳定 。例如在规模化猪场&…

YOLO 从入门到精通学习指南

一、引言 在计算机视觉领域,目标检测是一项至关重要的任务,其应用场景广泛,涵盖安防监控、自动驾驶、智能交通等众多领域。YOLO(You Only Look Once)作为目标检测领域的经典算法系列,以其高效、快速的特点受到了广泛的关注和应用。本学习指南将带领你从 YOLO 的基础概念…

Java 24新特性深度解析:从优化技巧到高手进阶指南

一、Java 24核心新特性详解 Java 24作为长期支持版本(LTS),带来了许多令人振奋的新特性,下面我们将深入探讨其中最值得关注的改进。 1. 字符串模板(String Templates)正式发布 字符串模板结束了Java字符串拼接的混乱时代&#…

《类和对象(中)》

引言: 上次我们主要学习了类的相关知识,今天我们就来学习类和对象(中),今天也会用到之前学习过的东西,可以说是前面知识的结合,较前面会难一点(打个预防针)。 一:类的默认成员函数…

为什么 AI 理解不了逻辑问题?

人类擅长“如果 A 则 B”,AI 擅长“这个像那个”。逻辑推理?对它来说是一场灾难性的认知挑战。 前言 在实际使用 AI(尤其是大型语言模型,比如 GPT、Claude、Gemini 等)时,我们常发现一个诡异的现象:它们文采斐然,甚至能讲出笑话,但一旦问点小学奥数或逻辑问题,就集体…

C# 使用SunnyUI控件 (VS 2019)

前言:建议下载源码,源码中包含了各种控件的用法案例。 下载 帮助文档: 文档预览 - Gitee.comGitee: SunnyUI: SunnyUI.NET 是基于.NET Framework 4.0、.NET8、.NET9 框架的 C# WinForm UI、开源控件库、工具类库、扩展类库、多页面开发框架。GitHub: h…

Spring Cloud: Nacos

Nacos Nacos是阿里巴巴开源的一个服务发现,配置管理和服务管理平台。只要用于分布式系统中的微服务注册,发现和配置管理,nacos是一个注册中心的组件 官方仓库:https://nacos.io/ Nacos的下载 Releases alibaba/nacos 在官网中…

Linux下的c/c++开发之操作mysql数据库

libmysqlclient-dev介绍(Linux 下的 Mysql C/C 开发包) libmysqlclient-dev 是一个开发包,在Linux环境下为使用 MySQL C API 进行开发的c/c程序员提供头文件(如 mysql.h)和静态库/动态库的链接信息(如 lib…

Java EE(Spring+Spring MVC+MyBatis)从入门到精通企业级应用开发教程——1初识MyBatis框架

1、MyBatis工作原理 MyBatis操作数据库流程分为8个步骤,具体介绍如下: (1)MyBatis读取核心配置文件mybatis-config.xml mybatis-config.xml核心配置文件主要配置了MyBatis的运行环境等信息。 (2)加载映射…

【许可证】Open Source Licenses

长期更新 扩展:shield.io装饰 开源许可证(Open Source Licenses)有很多种,每种都有不同的授权和限制,适用于不同目的。 默认的ISC🟰MIT License是否可商用是否要求开源衍生项目是否必须署名是否有专利授权…

ZooKeeper工作机制与应用场景

目录 1.1、概述1.2、选举机制1.2.1、选举触发条件1.2.2、选举规则1.2.3、选举过程详解 1.3、数据同步机制1.3.1、正常同步1.3.2、宕机同步 1.4、客户端常用命令1.5、应用场景1.5.1、配置管理1.5.2、命令服务1.5.3、分布式锁服务1.5.4、集群管理1.5.5、分布式ID1.5.6、分布式协调…

前端面经-VUE3篇(四)--pinia篇-基本使用、store、state、getter、action、插件

一、基本使用 1、什么是 Pinia? Pinia 是 Vue.js 的官方状态管理库,是 Vuex 的“升级版”。它专为 Vue 3 和 Composition API 设计,用于管理多个组件之间共享的数据(也叫“全局状态”)。 2、为什么需要状态管理库&a…

数据结构之图的遍历

图的遍历 图的遍历目的是访问图的每一个顶点恰好一次,,同时访问图中每条边恰好一 次。 对于无向图,常见的遍历方式有深度优先遍历(Depth-First Search, DFS) 和广度优先遍历(Breadth-First Search, BFS)。…

Ubuntu 第11章 网络管理_常用的网络配置命令

为了管理网络,Linux提供了许多非常有用的网络管理命令。利用这些命令,一方面可以有效地管理网络,另一方面出现网络故障时,可以快速进行诊断。本节将对Ubuntu提供的网络管理命令进行介绍。 11.2.1 ifconfig命令 关于ifconfig命令&…

Qt解决自定义窗口样式不生效问题

方法一: this->setAttribute(Qt::WA_StyledBackground, true); 方法二: 将类继承QWidget 改成继承 QFrame class MyWidget : public QFrame {} 方法三:重新实现QWidget的paintEvent函数时,使用QStylePainter绘制。 void p…

HNUST湖南科技大学-软件测试期中复习考点(保命版)

使用说明:本复习考点仅用于及格保命。软件测试和其他专业课不太一样,记忆的太多了,只能说考试的时候,想到啥就写啥,多写一点!多写一点!多写一点!(重要事情说三遍&#xf…

ES6 知识点整理

一、变量声明:var、let、const 的区别 作用域 var:函数作用域(函数内有效)。let/const:块级作用域({} 内有效,如 if、for)。 变量提升 var 会提升变量到作用域顶部(值为…