PostgreSQL如何查看事务所占有的锁?

news/2024/11/14 13:14:44/

表级锁命令LOCK TABLE

在PG中,显式地在表上加锁的命令为“LOCK TABLE”,此命令的语法如下:

LOCK [TABLE] [ONLY] name [,...][IN lockmode MODE] [NOWAIT]

语法中各项参数说明如下:

  1. name:表名
  2. lockmode:表级锁模式,即SHARE、EXCLUSIVE、ACCESS SHARE、ACCESS EXCLUSIVE、ROW SHARE、ROW EXCLUSIVE、SHARE UPDATE EXCLUSIVE、SHARE ROW EXCLUSIVE
  3. NOWAIT:如果没有NOWAIT这个关键字,当无法获得锁时会一直等待,而如果加了NOWAIT关键字,在无法立即获取该锁时,此命令会立即退出并且报错

在PG中,事务自己的锁是从不冲突的,因此一个事务可以在持有SHARE模式的锁时再请求ROW EXCLUSIVE锁,而不会出现自己的锁阻塞自己的情况

当事务要更新表中的数据时,应该申请ROW EXCLUSIVE锁,而不应该申请SHARE锁,因为在更新数据时,事务还是会对表加ROW EXCLUSIVE锁,想象一下,在两个并发的事务都请求SHARE锁后,开始更新数据前要对表加ROW EXCLUSIVE锁,但由于各自先前已加了SHARE锁,所以都要等待对方释放SHARE锁,因而出现死锁。从这个示例可以看出,如果涉及多种锁模式,那么事务应该总是最先请求最严格的锁模式,否则就容易出现死锁

行级锁命令

显式的行级锁命令是由SELECT命令后加如下子句来构成的:

SELECT ... FOR {UPDATE | SHARE} [OF table_name [,...]] [NOWAIT] [...]
  • NOWAIT关键字加上,如果无法获得锁则直接报错,而不会一直等待。
  • OF table_name明确指定表名字,那么只有被指定的表会被锁定,其他在SELECT中使用的表则不会
  • 不带OF table_name的FOR UPDATE或者FOR SHARE子句将锁定该命令中使用的所有表
  • 如果FOR UPDATE或者FOR SHARE应用于一个视图或者子查询,那么它将同样锁定该视图或者子查询中使用到的所有表
  • 主查询中引用了WITH查询时,WITH查询中的表并不会被锁定
  • 如果想要锁定WITH查询内的表行,需要在WITH查询内指定FOR UPDATE或者FOR SHARE关键字

锁的查看

我们经常需要查看一个事务产生了哪些锁,哪个事务被哪个事务阻塞了,若执行一条SQL语句时阻塞住了,需要查询为什么阻塞,是谁阻塞住的,这些信息可以通过查询系统视图“pg_locks”来得到。pg_locks视图中各列的描述如下:

列名称列类型引用描述
locktypetext被锁定的对象类型:relation、extend、page、tuple、transactionid、virtualxid、object、userlock、advisory
databaseoidpg_database.oid锁定对象的数据库OID,如果对象是一个共享对象,不属于任何数据库,此值为“0”,如果对象是“transaction ID”,此值为空
relationoidpg_class.oid如果对象不是表或只是表的一部分,则此值为“NULL”,否则此值是表的OID
pageinteger表中的页号,如果对象不是表行(tuple)或表页(relation page),则此值为“NULL”
tuplesmallint页内的行号(tuple)
virtualxidtext虚拟事务id
transactionidxid事务id
classidoidpg_class.oid包含该对象系统目录的id
objidoidany OID column对象在系统目录的oid
objsubidsmallint如果对象是表列(table column),此列的值为列号,这时classid和objid指向表
virtualtransactiontext持有或等待这把锁的虚拟事务id
pidinteger持有或等待这把锁的服务进程的PID,如果此锁是被一个两阶段提交的事务持有,则此值为NULL
modetext锁的模式名称,如“ACCESS SHARE”“SHARE”“EXCLUSIVE”等锁模式
grantedboolean如果锁已被持有,此值为True,如果等待获得此锁,则此值为False

上述中,描述事务id的字段有三个:

  • virtualxid
  • transactionid
  • virtualtransaction
  1. transactionid代表事务id,简写为“xid”
  2. virtualxid代表虚拟事务id,简写为“vxid”
  3. 每产生一个事务id,都会在pg_clog下的commit log文件中占用2bit
  4. 最早pg中本没有虚拟事务id,但是后来发现,有一些事务根本没有产生任何实质的变更,如一个只读事务或一个空事务,若在这种情况下也分配一个事务id会造成浪费,于是提出了虚拟事务id的概念
  5. 对于这类只读事务,值分配一个虚拟事务id,而不是实际分配一个真实的事务id,这样就不需要在commit log中占用2bit的空间了

pg_locks这张视图的字段分为以下两部分:

  • virtualtransaction之前的字段(不包括virtualtransaction字段),我们称其为“第一部分”,用于描述锁定对象(Locked Object)信息
  • virtualtransaction之后的字段(包括virtualtransaction字段),我们称其为“第二部分”,用于描述持有锁或等待锁的session信息

了解上述概念后,可以容易理解virtualxid和virtualtransaction两个字段的意思:

  • virtualxid在第一部分字段中,表示锁对象是一个virtualxid
  • virtualtransaction表示持有锁或等待锁session的虚拟事务id

表锁实操

1.先开一个psql窗口,命令如下
image

第一个窗口,查询PID,并锁定一张表。

2.第二个窗口中查看数据库中的锁的情况
image
sql命令:

select locktype,relation::regclass as rel,virtualxid as vxid,transactionid as xid,virtualtransaction as vxid2,pid,mode,granted from pg_locks where pid = 12264;

通过上述图片可以看出:

  • 第一行显示的是事务在自己的“virtualxid”上加的ExclusiveLock锁,这是必定会加上的
  • 第二行才是我们实际在表上加的锁“AccessExclusiveLock”

3.新增一个窗口,显示地对表加锁
image

执行sql语句发现,该窗口的锁表语句会被阻塞住

4.查看两个进程的锁情况
image

  • 发现两个进程都对表加了锁
  • 进程12264中的granted字段为t,说明它获得了这把锁
  • 进程21052中的granted字段为f,说明该进程没有获得这把锁,从而被阻塞

行锁实操

1.第一个窗口执行如下操作(在加表锁的基础上加行锁)
image

2.第二个窗口中查看数据库中的锁的情况
image

行锁不仅会在表上加意向锁,也会在相应的主键上加意向锁。其中“jxx_test_pkey”就是表的主键。

3.另一个窗口加行锁
image
该窗口阻塞

4.第二个窗口中查看数据库中的锁的情况
image

xid为739的锁被京城12264持有了,所以21052的进程获取锁标识为False

pg_locks并不能显示出每个行锁的信息,因为行锁信息并不会被记录到共享内存中。如果记录到内存,意味着对表做全表更新时,表有多少行就需要在内存中记录多少条行锁信息,那么内存会吃不消,所以postgreSQL设计成不在内存中记录行锁信息。


思考:如何获取进程是在哪一行上被阻塞的?


http://www.ppmy.cn/news/337044.html

相关文章

京东双 11 大促价疑遭提前泄露;库克:iPhone 11 中国定价策略成功;GitLab 重大安全版本更新 | 极客头条...

整理 | 屠敏 快来收听极客头条音频版吧,智能播报由标贝科技提供技术支持。 「CSDN 极客头条」,是从 CSDN 网站延伸至官方微信公众号的特别栏目,专注于一天业界事报道。风里雨里,我们将每天为朋友们,播报最新鲜有料的新…

11月1日科技资讯|京东双 11 大促价疑遭提前泄露;库克:iPhone 11 中国定价策略成功;GitLab 重大安全版本更新 | 极客头条

「CSDN 极客头条」,是从 CSDN 网站延伸至官方微信公众号的特别栏目,专注于一天业界事报道。风里雨里,我们将每天为朋友们,播报最新鲜有料的新闻资讯,让所有技术人,时刻紧跟业界潮流。 快讯通知 吴德周&…

【华为OD机试真题 C语言】25、考勤信息 | 机试真题+思路参考+代码解析

文章目录 一、题目🎃题目描述🎃输入输出🎃样例1🎃样例2 二、思路参考三、代码参考 作者:KJ.JK 🍂个人博客首页: KJ.JK 🍂专栏介绍: 华为OD机试真题汇总,定期…

2.21 alarm函数 2.22setitimer定时器函数

2.21 alarm函数 #include <unistd.h> unsigned int alarm(unsigned int seconds);功能&#xff1a;设置定时器&#xff08;闹钟&#xff09;。函数调用&#xff0c;开始倒计时&#xff0c;当倒计时为0的时候&#xff0c; 函数会给当前的进程发送一个信号&#xff1a;SIG…

【实战】体验训练Geneface

一.环境 conda activate geneface export PYTHONPATH./ CUDA_VISIBLE_DEVICES0 python tasks/run.py --configegs/datasets/lrs3/lm3d_syncnet.yaml --exp_namelrs3/syncnet 训练这篇出过的一些奇奇怪怪的问题基本上都记录在【环境搭建】40系一些奇奇怪怪的环境问题_weixin_50…

达人评测 i9 12900H和i5 12500h选哪个

i5 12500H为4大核8小核&#xff0c;12核心16线程设计&#xff0c;CPU主频 2.5GHz 最高睿频 4.5GHz 三级缓存为18MB 功耗(TDP) 45W.选 i5 12500H还是i9 12900H这些点很重要 http://www.adiannao.cn/dy i9 12900H采用7nm 制作工艺14核心20线程&#xff0c;主频为2.5GHz&#xff0…

大数据营销【3】

1.大数据获取的个人信息比传统调研获得的个人信息真实性 A.更低 B.更高 C.相同 D.不确定 2.分类变量使用&#xff08;&#xff09;建立预测模型 A.分类树 B.回归树 C.决策树 D.离散树 3.面向用户提供大数据一站式部署方案&#xff0c;包括数据中心和服务器等硬件、数据分析…

重磅推荐 | 孩子学习神器,双十二必买好物

受疫情黑天鹅的影响&#xff0c;线上智慧教学突飞猛进发展。专业、高效的特点带给学生不输于传统线下教育的感受&#xff0c;不少人对智慧教育的看法有所改观。但还是有不少家长认为教育线上化比传统教育缺乏了线下课堂教育的强制性&#xff0c;认为实用性并不高。可在疫情爆发…