梧桐数据库锁处理过程

遇到一个奇怪的现象,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 EXCLUSIVESHARE UPDATE EXCLUSIVE 锁,这允许事务修改数据,但不允许其他事务同时修改同一行。
  3. INSERTINSERT 操作也会申请 ROW EXCLUSIVE 锁,以确保新插入的行不会被其他事务同时修改。
  4. ALTER TABLEALTER TABLE 操作,如添加或删除列,会申请 ACCESS EXCLUSIVE 锁,因为这些操作需要修改表结构,可能会影响所有行。
  5. TRUNCATE TABLETRUNCATE TABLE 操作会申请 ACCESS EXCLUSIVE 锁,因为它需要删除表中的所有行,这是一个重量级操作,需要确保没有其他事务正在访问表。
  6. DROP TABLEDROP TABLE 操作同样需要 ACCESS EXCLUSIVE 锁,因为它会完全删除表,这是一个不可逆的操作,需要确保没有其他事务正在使用表。
  7. LOCK TABLE :使用 LOCK TABLE 命令时,可以指定不同的锁模式,如 ACCESS SHAREROW SHAREROW EXCLUSIVESHARE UPDATE EXCLUSIVESHARESHARE ROW EXCLUSIVEACCESS EXCLUSIVE

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

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

  1. 确定持有锁的事务的进程ID(procpid)。
  2. 使用 pg_cancel_backendpg_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() 函数也可以杀掉进程。

相关推荐
薛晓刚1 小时前
当MySQL的int不够用了
数据库
SelectDB技术团队1 小时前
Apache Doris 在菜鸟的大规模湖仓业务场景落地实践
数据库·数据仓库·数据分析·apache doris·菜鸟技术
星空下的曙光2 小时前
mysql 命令语法操作篇 数据库约束有哪些 怎么使用
数据库·mysql
小楓12012 小时前
MySQL數據庫開發教學(一) 基本架構
数据库·后端·mysql
染落林间色2 小时前
达梦数据库-实时主备集群部署详解(附图文)手工搭建一主一备数据守护集群DW
数据库·sql
颜颜yan_2 小时前
企业级时序数据库选型指南:从传统架构向智能时序数据管理的转型之路
数据库·架构·时序数据库
lichenyang4532 小时前
管理项目服务器连接数据库
数据库·后端
沙振宇2 小时前
【数据库】通过‌phpMyAdmin‌管理Mysql数据
数据库·mysql
杨云龙UP3 小时前
CentOS Linux 7 (Core)上部署Oracle 11g、19C RAC详细图文教程
数据库·oracle
ezl1fe3 小时前
RAG 每日一技(十八):手写SQL-RAG太累?LangChain的SQL智能体(Agent)前来救驾!
数据库·人工智能·后端