死锁-MySQL

作者阿里云代理 文章分类 分类:linux图文教程 阅读次数 已被围观 337

1、死锁

在操作系统中,死锁是指两个或两个以上的进程,每个进程都无限等候被改组进程中另一个进程所占有的资源,因而永远无法得到资源,这种现象称为进程死锁。

那么在数据库中,我们将操作系统对死锁的界说进行简略替换,将进程替换为事务即可。

数据库死锁是指两个或两个以上的事务,每个事务都在无限等候被改组事务中另一个事务所占有的资源,因而无法得到资源。

2、死锁必要条件

只要发生了死锁,这四个条件必定存在。

  1. 互斥使用(独占资源)

在数据库中,互斥使用的资源大部分都是表和行。

  1. 占有且等候

一个事务先确定了行A,然后又请求确定行B;另一个事务先请求确定了行B,然后有请求确定行A;当这两个事务以一种时序履行时就会产生死锁。

  1. 不可抢占

事务与事务之间是阻隔的,必定不可以一个事务抢占另一个事务的资源,有必要要等候事务资源释放资源。

  1. 循环等候

当事务和资源形成一条有向有环图时。使用资源分配图来表明一下(蓝色先表明有回路):

1.png

3、SQL示例

-- 创建用户余额表 CREATE TABLE `user_balance` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', `balance` int NOT NULL COMMENT '余额',
  PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '用户余额'; -- 插入2条记录 INSERT INTO `user_balance` (`balance`) VALUES (1); INSERT INTO `user_balance` (`balance`) VALUES (1); -- 事务A BEGIN; UPDATE `user_balance` SET `balance`=`balance`+1 where id=1; UPDATE `user_balance` SET `balance`=`balance`+1 where id=2; COMMIT; -- 事务B BEGIN; UPDATE `user_balance` SET `balance`=`balance`+1 where id=2; UPDATE `user_balance` SET `balance`=`balance`+1 where id=1; COMMIT;

如果恰好事务A和事务B都履行了第一行UPDATE,接着事务A和事务B都去履行第二条UPDATE语句,此刻发现id=1和id=2的数据都被确定且不是自己,那么事务A和B都在彼此等候锁释放,则陷入了死锁状态。

4、处理方案

为了处理死锁问题,数据库实现了各种死锁检测和死锁超时机制。InnoDB存储引擎可以检测到死锁的循环依赖并立即返回操作。

InnoDB目前处理死锁的方法是将持有最少行排他锁的事务进行回滚。

5、死锁复现

依照使用上面的SQL在MySQL 8.0版本履行SQL进行死锁复现,截图如下:

  1. 事务A正常履行

2.png

  1. 事务B被回滚

3.png

6、总结

  1. MySQL 的死锁并不可怕,死锁后只需要在事务代码进行重试即可(官方建议)

7、参考

  1. 高性能MySQL(第三版)
本公司销售:阿里云、腾讯云、百度云、天翼云、金山大米云、金山企业云盘!可签订合同,开具发票。

我有话说: