梧桐数据库锁处理过程

遇到一个奇怪的现象,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() 函数也可以杀掉进程。

相关推荐
2501_941111342 小时前
Python上下文管理器(with语句)的原理与实践
jvm·数据库·python
程序员卷卷狗7 小时前
MySQL 高可用方案:主从 + MHA + ProxySQL + PXC 的实战应用与架构思考
数据库·mysql·架构
千千寰宇7 小时前
[数据库/数据结构] LSM-Tree :结构化的日志合并树——NewSQL数据库的基石
数据库
韩立学长8 小时前
基于Springboot的研学旅游服务系统5u416w14(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·旅游
isNotNullX8 小时前
怎么理解ETL增量抽取?
数据库·数据仓库·etl·企业数字化
谅望者9 小时前
数据分析笔记14:Python文件操作
大数据·数据库·笔记·python·数据挖掘·数据分析
l1t9 小时前
调用python函数的不同方法效率对比测试
开发语言·数据库·python·sql·duckdb
武昌库里写JAVA9 小时前
微擎服务器配置要求,微擎云主机多少钱一年?
java·vue.js·spring boot·后端·sql
honortech9 小时前
MySQL 8 连接报错:Public Key Retrieval is not allowed
数据库·mysql
q***82919 小时前
MySQL--》如何通过选择合适的存储引擎提高查询效率?
数据库·mysql·adb