网站首页 > 数据编程 正文
Mysql死锁解决
什么是死锁
所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。
产生死锁条件
产生死锁的四个必要条件:
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
死锁的影响
当产生某表死锁的一开始,所有涉及这张表的操作都将受到阻塞。假设这张表在业务逻辑上是读写频繁的,那就会使很多操作在那里排队等待,而排队等待会占用数据库连接,当该达到该数据库连接数的最大承载数之后,就会使所有数据库操作均无法再继续下去,致使数据库各项指标异常,导致整个环境崩溃。
在生产环境中出现这种问题,那是相当致命的,当发现数据库指标异常时因快速处理!
如何排查死锁
查询数据库进程
主要看 State 字段,如果出现大量 waiting for ..lock 即可判定死锁:
SHOW FULL PROCESSLIST;
注意:需要拥有 root 组权限(supper),否则只能看到当前用户的进程,无法查询所有。
查看当前的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
INNODB_TRX 表包含信息关于每个事务(排除只读事务)当前执行的在 InnoDB,包含是否事务是等待一个锁, 当事务启动后, SQL 语句事务是正在执行。
INNODB_TRX Columns 相关列信息:
字段 | 描述 |
trx_id | innodb 存储引擎内部事务唯一的事务 id。 |
trx_state | 当前事务的状态。 |
trx_started | 事务开始的时间。 |
trx_requested_lock_id | 等待事务的锁 id,如 trx_state 的状态为 LOCK WAIT,那么该值代表当前事务之前占用锁资源的 id,如果 trx_state 不是 LOCK WAIT 的话,这个值为 null。 |
trx_wait_started | 事务等待开始的时间。 |
trx_weight | 事务的权重,反映了一个事务修改和锁住的行数。在 innodb 的存储引擎中,当发生死锁需要回滚时,innodb 存储引擎会选择该值最小的事务进行回滚。 |
trx_mysql_thread_id | 正在运行的 mysql 中的线程 id,show full processlist 显示的记录中的 thread_id。 |
trx_query | 事务运行的sql语句,在实际中发现,有时会显示为 null 值,当为 null 的时候,就是 t2 事务中等待锁超时直接报错(ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction)后,trx_query 就显示为 null 值。 比如事务 t2 正在运行 trx_query: update test.t1 set b='t2' where a=1 的 sql 语句,t1 先执行,所以是 trx_state: RUNNING 先申请的资源一直在运行,而 t2 后run 的所以是 trx_state: LOCK WAIT 一直在等待 t1 执行完后释放资源。 但是并不能仔细判断锁的一些详细情况,我们需要再去看当前锁定的事务表数据。 |
查看当前锁定的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
INNODB_LOCKS 表包含信息关于每个锁一个 InnoDB 事务已经请求,但是没有获得锁,每个 lock 一个事务持有是堵塞另外一个事务。INNODB_LOCKS Columns 相关列信息:
字段 | 描述 |
lock_id | 锁的 id 以及被锁住的空间 id 编号、页数量、行数量。 |
lock_trx_id | 锁的事务 id。 |
lock_mode | 锁的模式。 |
lock_type | 锁的类型,表锁还是行锁。 |
lock_table | 要加锁的表。 |
lock_index | 锁的索引。 |
lock_space | innodb 存储引擎表空间的 id 号码。 |
lock_page | 被锁住的页的数量,如果是表锁,则为 null 值。 |
lock_rec | 被锁住的行的数量,如果表锁,则为 null 值。 |
lock_data | 被锁住的行的主键值,如果表锁,则为 null 值。 |
如以下查询 :
mysql> select * from INNODB_LOCKSG
输出行一:
lock_id: 3015646:797:3:2
lock_trx_id: 3015646
lock_mode: X
lock_type: RECORD
lock_table: test.t1
lock_index: PRIMARY
lock_space: 797
lock_page: 3
lock_rec: 2
lock_data: 1
行二:
lock_id: 3015645:797:3:2
lock_trx_id: 3015645
lock_mode: X
lock_type: RECORD
lock_table: test.t1
lock_index: PRIMARY
lock_space: 797
lock_page: 3
lock_rec: 2
lock_data: 1
这里我们可以看到当前的锁信息了,2 个事务都锁定了,看相同的数据 lock_space: 797、lock_page: 3、lock_rec: 2 可以得出事务 t1 和事务 t2 访问了相同的 innodb 数据块,再通过 lock_data 字段信息 lock_data: 1,看到锁定的数据行都是主键为 1 的数据记录,可见 2 个事务 t1 和 t2 都申请了相同的资源,因此会被锁住,事务在等待。
通过 lock_mode: X 值也可以看出事务 t1 和 t2 申请的都是排它锁。
PS:当执行范围查询更新的时候,这个 lock_data 的值并非是完全准确。当我们运行一个范围更新时,lock_data 只返回最先找到的第一行的主键值 id;另外如果当前资源被锁住了,与此同时由于锁住的页因为 InnoDB 存储引擎缓冲池的容量,而导致替换缓冲池页面,再去查看 INNODB_LOCKS 表时,这个 lock_data 会显示未 NULL 值,意味着 InnoDB 存储引擎不会从磁盘进行再一次查找。
查看当前等锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
INNODB_LOCK_WAITS 表包含了 blocked 的事务的锁等待的状态。当事务量比较少,我们可以直观的查看,当事务量非常大,锁等待也时常发生的情况下,这个时候可以通过 INNODB_LOCK_WAITS 表来更加直观的反映出当前的锁等待情况。
INNODB_LOCK_WAITS Columns 相关列信息:
字段 | 描述 |
requesting_trx_id | 申请锁资源的事务 id。 |
requested_lock_id | 申请的锁的 id。 |
blocking_trx_id | 阻塞的事务 id。 |
blocking_lock_id | 阻塞的锁的 id。 |
如以下查询:
mysql> select * from INNODB_LOCK_WAITSG
输出:
requesting_trx_id: 3015646
requested_lock_id: 3015646:797:3:2
blocking_trx_id: 3015645
blocking_lock_id: 3015645:797:3:2
这里我们可以看到事务 t1(3015646) 申请了锁资源,而事务 t2(3015645) 则阻塞了事务 t1 的申请。
收集死锁信息
- 利用命令 SHOW ENGINE INNODB STATUS 查看死锁原因。
- 调试阶段开启 innodb_print_all_deadlocks,收集所有死锁日志。
如何处理死锁
查询对应死锁的数据库进程,可以直接杀掉
kill 进程ID
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
虽然不能完全避免死锁,但可以使死锁的数量减至最少。将死锁减至最少可以增加事务的吞吐量并减少系统开销,因为只有很少的事务回滚,而回滚会取消事务执行的所有工作。由于死锁时回滚而由应用程序重新提交。
如何防止死锁
- 使用事务,不使用 lock tables。
- 保证没有长事务。
- 操作完之后立即提交事务,特别是在交互式命令行中。
- 如果在用 (SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE),尝试降低隔离级别。
- 修改多个表或者多个行的时候,将修改的顺序保持一致。
- 创建索引,可以使创建的锁更少。
- 最好不要用 (SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE)。
如果上述都无法解决问题,那么尝试使用 lock tables t1, t2, t3 锁多张表。
猜你喜欢
- 2024-11-09 死锁Deadlock内测资格怎么拿,获取内测资格教程来了
- 2024-11-09 死锁Deadlock崩溃,无法启动怎么处理
- 2024-11-09 图解Java中的锁:什么是死锁?怎么排查死锁?怎么避免死锁?
- 2024-11-09 「C#.NET 拾遗补漏」12:死锁和活锁的发生及避免
- 2024-11-09 死锁详解:常见死锁案例、条件,如何避免出现死锁?
- 2024-11-09 死锁下载不了/下载慢/下载报错/无法下载的解决办法分享
- 2024-11-09 数据库死锁排查思路分享引言 数据库死锁查询命令
- 2024-11-09 什么是死锁以及避免死锁 什么是死锁以及避免死锁的方法
- 2024-11-09 MySql死锁问题如何排查 mysql死锁的情况
- 2024-11-09 死锁Deadlock匹配不到人,匹配失败解决方法在这
- 最近发表
- 标签列表
-
- oraclepdb (60)
- vncviewermac (62)
- sqlservermax (58)
- mysqlcanal (61)
- mysql:commandnotfound (56)
- mysqlexplainfiltered (56)
- python位运算符 (59)
- linuxfind-name模糊查询文件 (60)
- centos7systemctl (76)
- mysqlgt (55)
- nc命令 (66)
- dockerfilecp (55)
- 单行子查询返回多个行解决办法 (58)
- ssh-2.0-openssh_7.4 (56)
- vue图片裁剪 (59)
- anyvideoconverterpro (62)
- pscache (58)
- hdfsfsck (63)
- nacos源码 (69)
- lambdawrapper (60)
- 安装jdk11 (60)
- 什么是聚簇索引 (62)
- 锁升级过程 (58)
- bootcdn (64)
- axurerp9mac破解版 (58)