pg锁介绍

AccessShareLock:是共享读锁,任何只读取表而不修改它的查询都将获得这种锁模式,此时不允许DDL
ExclusiveLock:文档没找到合适的解释,猜测是全局资源排他锁,对应每个事务的资源排他锁
RowShareLock:select for update ,select for share情况下会出现此锁,此时不允许DML和DDL
RowExclusiveLock:dml会产生此锁,此时不允许dml相同记录,也不允许DDL
AccessExclusiveLock: create、ALTER TABLE、DROP TABLE、TRUNCATE、REINDEX、CLUSTER、VACUUM FULL和REFRESH MATERIALIZED VIEW(不带CONCURRENTLY) 表会产生此锁。这种模式保证持有者是访问该表的唯一事务。此锁会阻塞查询
ShareUpdateExclusiveLock:由VACUUM(不带FULL)、ANALYZE、CREATE INDEX CONCURRENTLY、CREATE STATISTICS和ALTER TABLE VALIDATE以及其他ALTER TABLE的变体获得此锁,这种模式保护一个表不受并发模式改变和VACUUM运行的影响。
ShareLock:CREATE INDEX (WITHOUT CONCURRENTLY)会获得此锁,这种模式保护一个表不受并发数据改变的影响,即不能修改此表相关的数据和表结构。
ShareRowExclusiveLock:这种模式保护一个表不受并发数据修改所影响,并且是自排他的,这样在一个时刻只能有一个会话持有它。

AccessShareLock

场景一
session 1;
wjz=# begin;
BEGIN
wjz=# select * from test;
id

1
3
6
2
4
5
(6 rows)

session 2;
select a.pid,b.mode,a.query from pg_stat_activity a left join pg_locks b on a.pid=b.pid;
pid | mode | query
-------±----------------±-----------------------------------------------------------------------------------------
14906 | AccessShareLock | select * from test;
14906 | ExclusiveLock | select * from test;

发现查询除了AccessShareLock 外还有ExclusiveLock 。

RowShareLock

场景二
session 1;
wjz=# begin;
BEGIN
wjz=# select * from test for update;
id

1
3
6
2
4
5
(6 rows)

session 2;
postgres=# select a.pid,b.mode,a.query from pg_stat_activity a left join pg_locks b on a.pid=b.pid order by a.pid ;
pid | mode | query

-------±----------------±----------------------------------------------------------------------------------------------
14906 | RowShareLock | select * from test for update;
14906 | ExclusiveLock | select * from test for update;
14906 | ExclusiveLock | select * from test for update;

session 1;
wjz=# begin;
BEGIN
wjz=# select * from test for share;
id

1
3
6
2
4
5
(6 rows)
session 2;
postgres=# select a.pid,b.mode,a.query from pg_stat_activity a left join pg_locks b on a.pid=b.pid order by a.pid ;
pid | mode | query

-------±----------------±----------------------------------------------------------------------------------------------
14906 | RowShareLock | select * from test for share;
14906 | ExclusiveLock | select * from test for share;
14906 | ExclusiveLock | select * from test for share;

session 3;
wjz=# begin;
BEGIN
wjz=# update test set id=2 where id<3;

在select for share下也是无法DML和DDL这些表,此处也有ExclusiveLock。

RowExclusiveLock

场景三

session 1;
wjz=# begin;
BEGIN
wjz=# update test set id=3 where id<5;
UPDATE 4

session 2;
postgres=# select a.pid,b.mode,a.query from pg_stat_activity a left join pg_locks b on a.pid=b.pid order by a.pid ;
pid | mode | query

-------±-----------------±---------------------------------------------------------------------------------------------
14906 | RowExclusiveLock | update test set id=3 where id<5;
14906 | ExclusiveLock | update test set id=3 where id<5;
14906 | ExclusiveLock | update test set id=3 where id<5;

session 1;
wjz=# begin;
BEGIN
wjz=# insert into test values(10);
INSERT 0 1
wjz=#

session 2;
postgres=# select a.pid,b.mode,a.query from pg_stat_activity a left join pg_locks b on a.pid=b.pid order by a.pid ;
pid | mode | query

-------±-----------------±---------------------------------------------------------------------------------------------
14906 | RowExclusiveLock | insert into test values(10);
14906 | ExclusiveLock | insert into test values(10);
14906 | ExclusiveLock | insert into test values(10);

session 1;
wjz=# begin;
BEGIN
wjz=# delete from test where id<2;
DELETE 1

session 2;
postgres=# select a.pid,b.mode,a.query from pg_stat_activity a left join pg_locks b on a.pid=b.pid order by a.pid ;
pid | mode | query

-------±-----------------±---------------------------------------------------------------------------------------------
14906 | RowExclusiveLock | delete from test where id<2;
14906 | ExclusiveLock | delete from test where id<2;
14906 | ExclusiveLock | delete from test where id<2;

AccessExclusiveLock

场景四

session 1;
wjz=# begin;
BEGIN
wjz=# create table student(name varchar(10));
CREATE TABLE

wjz=# begin;
BEGIN
wjz=# alter table test add column name varchar(20);
ALTER TABLE

postgres=# select a.pid,b.mode,a.query from pg_stat_activity a left join pg_locks b on a.pid=b.pid order by a.pid ;
pid | mode | query

-------±--------------------±------------------------------------------------------------------------------------------

14906 | ExclusiveLock | create table student(name varchar(10));
14906 | AccessExclusiveLock | create table student(name varchar(10));
14906 | ExclusiveLock | create table student(name varchar(10));
14906 | AccessShareLock | create table student(name varchar(10));
14906 | ExclusiveLock | alter table test add column name varchar(20);
14906 | ExclusiveLock | alter table test add column name varchar(20);
14906 | AccessExclusiveLock | alter table test add column name varchar(20);

session 3;
wjz=# begin;
BEGIN
wjz=# update test set id=2 where id<3; —出现锁等待

ShareUpdateExclusiveLock

场景五
session 1;
wjz=# CREATE INDEX CONCURRENTLY idx_test1 on test(name) ;
CREATE INDEX

session 2;
postgres=# select a.pid,b.mode,a.query from pg_stat_activity a left join pg_locks b on a.pid=b.pid order by a.pid ;
pid | mode | query

-------±-------------------------±-------------------------------------------------------------------------------------
14906 | RowExclusiveLock | CREATE INDEX CONCURRENTLY idx_test1 on test(name) ;
14906 | RowExclusiveLock | CREATE INDEX CONCURRENTLY idx_test1 on test(name) ;
14906 | RowExclusiveLock | CREATE INDEX CONCURRENTLY idx_test1 on test(name) ;
14906 | ExclusiveLock | CREATE INDEX CONCURRENTLY idx_test1 on test(name) ;
14906 | AccessExclusiveLock | CREATE INDEX CONCURRENTLY idx_test1 on test(name) ;
14906 | ExclusiveLock | CREATE INDEX CONCURRENTLY idx_test1 on test(name) ;
14906 | ShareUpdateExclusiveLock | CREATE INDEX CONCURRENTLY idx_test1 on test(name) ;

不加concurrently关键字的DDL会阻塞dml和查询等
14906 | ExclusiveLock | create index idx_test2 on test(name) ;
14906 | AccessExclusiveLock | create index idx_test2 on test(name) ;
14906 | ExclusiveLock | create index idx_test2 on test(name) ;
14906 | ShareLock | create index idx_test2 on test(name) ;

session 3;
wjz=# select * from test; —发生等待

ShareRowExclusiveLock

这个锁才疏学浅,没有模拟出来,后续遇到再补充。

官网锁兼容性表格:
postgresql 锁小测验
实验总结
(1)ExclusiveLock这个锁出现在每个会话中,从字面意思理解是互斥锁,但从实验中发现此锁对表的其他锁不造成冲突,应该是负责管理事务本身资源方面的锁的占用。
(2)AccessShareLock与ShareUpdateExclusiveLock都不阻塞读写,但会阻塞DDL。
(3)AccessExclusiveLock会阻塞读写,但与ShareUpdateExclusiveLock共同存在下,不阻塞读写(具体原因估计和锁的优先级或者加锁顺序有关)。
(4)RowExclusiveLock:一般是DML产生的,但DDL某些情况下也会产生。
postgresql锁的资料网上太少了,测试完还是晕乎乎的,掌握一下锁出问题的解决办法吧!

postgresql 锁小测验

查看等待锁的SQL:
select a.pid,a.usename,a.query,a.wait_event_type,b.mode,now()-a.xact_start as xid_startime from pg_stat_activity a join pg_locks b on a.pid=b.pid where not b.granted order by xid_startime asc;
查看当前数据库执行SQL情况
select datname,pid,usename,application_name,client_addr,now()-xact_start as xid_startime,now()-query_start as query_startime,now()-state_change as state_changetime,wait_event_type,state,query from pg_stat_activity where query !=’’ order by xid_startime asc;
查询阻塞源的函数
select pg_blocking_pids(23224);
取消阻塞源的函数:
select pg_terminate_backend(14906); 可释放阻塞源,这个相当于杀掉会话进程
select PG_CANCEL_BACKEND(14906);取消后台操作,回滚未提交事务,但不会杀掉会话进程

相关文章:

  • 2021-09-26
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-09-12
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-08-07
  • 2022-02-25
  • 2022-12-23
  • 2022-12-23
  • 2021-12-24
  • 2021-10-12
相关资源
相似解决方案