梧桐数据库锁处理过程

遇到一个奇怪的现象,select 和 delete 表时正常执行,但 truncate 和 drop 表时会一直运行,也不报错。

一、查了些资料才发现问题的原因,总结如下:

" drop table " 和 " truncate table " 需要申请排它锁 " ACCESS EXCLUSIVE ", 执行这个命令卡住时,说明此时这张表上还有操作正在进行,比如查询等,那么只有等待这个查询操作完成," drop table " 或" truncate table "或者增加字段的 SQL 才能获取这张表上的 " ACCESS EXCLUSIVE " 锁 ,操作才能进行下去。

补充内容:产生锁冲突的操作及锁类型

在数据库操作中,不同的SQL命令会申请不同类型的锁,以确保数据的一致性和完整性。以下是一些常见的操作及其申请的锁类型:

  1. SELECT :默认情况下,SELECT 操作会申请共享锁(Share Locks),这意味着多个事务可以同时读取数据,但不能修改。共享锁的类型通常是 ACCESS SHARE。
  2. UPDATE、DELETE :这些操作会申请排它锁(Exclusive Locks),但不是 ACCESS EXCLUSIVE。它们通常申请 ROW EXCLUSIVE 或 SHARE UPDATE EXCLUSIVE 锁,这允许事务修改数据,但不允许其他事务同时修改同一行。
  3. INSERT :INSERT 操作也会申请 ROW EXCLUSIVE 锁,以确保新插入的行不会被其他事务同时修改。
  4. ALTER TABLE :ALTER TABLE 操作,如添加或删除列,会申请 ACCESS EXCLUSIVE 锁,因为这些操作需要修改表结构,可能会影响所有行。
  5. TRUNCATE TABLE :TRUNCATE TABLE 操作会申请 ACCESS EXCLUSIVE 锁,因为它需要删除表中的所有行,这是一个重量级操作,需要确保没有其他事务正在访问表。
  6. DROP TABLE :DROP TABLE 操作同样需要 ACCESS EXCLUSIVE 锁,因为它会完全删除表,这是一个不可逆的操作,需要确保没有其他事务正在使用表。
  7. LOCK TABLE :使用 LOCK TABLE 命令时,可以指定不同的锁模式,如 ACCESS SHARE、ROW SHARE、ROW EXCLUSIVE、SHARE UPDATE EXCLUSIVE、SHARE、SHARE ROW EXCLUSIVE 或 ACCESS EXCLUSIVE。

当一个事务持有共享锁(如 ACCESS SHARE)时,其他事务可以读取数据但不能修改。而当一个事务尝试获取 ACCESS EXCLUSIVE 锁时,它会等待所有现有的共享锁释放。如果存在未完成的查询或其他操作,它们持有的共享锁会阻止 ACCESS EXCLUSIVE 锁的获取,从而导致 TRUNCATE TABLE 或 DROP TABLE 操作卡住。

为了解决这种锁冲突,可以采取以下步骤:

  1. 确定持有锁的事务的进程ID(procpid)。
  2. 使用 pg_cancel_backend 或 pg_terminate_backend 函数终止持有锁的事务。

这些操作应该谨慎执行,因为终止事务可能会导致数据不一致或其他问题。在执行这些操作之前,最好先评估影响,并确保有适当的数据备份。

二、知道原因后解锁步骤如下:

1.检索出死锁进程的ID。

SELECT * FROM pg_stat_activity WHERE datname='死锁的数据库ID ';

检索出来的字段中,【 wating 】字段,数据为t的那条,就是锁等待的进程。找到对应的【 procpid 】列的值。

注:

数据库中有两种基本的锁:排它锁(Exclusive Locks)和共享锁(Share Locks)。 如果数据对象加上排它锁,则其他的事务不能对它读取和修改。 如果加上共享锁,则该数据库对象可以被其他事务读取,但不能修改。 锁定模式:ACCESS SHARE,ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE,SHARE ROW EXCLUSIVE,EXCLUSIVE,ACCESS EXCLUSIVE。 LOCK TABLE department1 IN ACCESS EXCLUSIVE MODE;

查看锁的会话,确定锁的来源:

select * from pg_stat_activity_global where current_query<>''; select * from oushu_lock_status where pid = 38099 ; select * from oushu_lock_status where relation = 955982; select * from pg_stat_activity_global where procpid=630657; select pg_terminate_backend(27189)

2.将进程杀掉。

SELECT pg_cancel_backend('死锁那条数据的procpid值 ');

结果:运行完后,再次更新这个表,sql 顺利执行。

如果 pg_stat_activity_global 没有记录,则查询 pg_locks 是否有这个对象的锁

复制代码
select oid,relname from pg_class where relname='table name';
select locktype,pid,relation,mode,granted,* from pg_locks where relation='上面查询出来的oid';
SELECT pg_cancel_backend('进程ID ');

另外,也可以使用 pg_terminate_backend() 函数也可以杀掉进程。

相关推荐
AIgorithmGEEK4 小时前
MySQL 索引全解(下):建、查、删实战与知识速查表
数据库·mysql·b+树·索引
唠点键盘之外的6 小时前
26 向量数据库实战:从 0 搭一条能用的检索链路(pgvector + Spring AI)
数据库·人工智能·spring
云和恩墨7 小时前
数据库监控简史:监控不止于告警——从图表大爆发到健康管理闭环
数据库
ly76897 小时前
MongoDB 事务开销实测:快照隔离下的写冲突、重试与分片事务边界
数据库·mongodb·事务·分片集群·快照隔离·写冲突
豆角焖肉7 小时前
Spring AOP 自定义注解实现系统操作日志
数据库·自定义注解·springaop·操作日志·aop 切面
金伟API10248 小时前
不会写复杂SQL怎么办?
数据库·sql
执笔为剑8 小时前
2.1.2-1、V8R3迁移到V8R6-Oracle兼容特性
数据库
江湖有缘9 小时前
Docker实战 | 使用Docker部署rmoments社交平台
jvm·docker·oracle
geovindu9 小时前
sql:Search-Optimized SQL Queries using mysql 9.0
android·数据库·sql·mysql·数据库开发·数据库架构
for_ever_love__9 小时前
MySQL SELECT 与 WHERE 优化实战:可搜索条件、联合索引与执行计划
数据库·mysql·oracle·select·where·条件优化·查询优化技巧