MySQL 死锁了,怎么办?

港控/mmm° 2024-04-07 11:56 180阅读 0赞

之前分享过 MySQL 死锁的文章,然后很多读者对「插入意向锁」认识很迷糊。

大家误以为「插入意向锁」是意向锁,也就是表锁,确实这个名字很让人误解。

但是,实际上「插入意向锁」不是意向锁,而是特殊的间隙锁,属于行级锁,注意是「特殊」的间隙锁,并不是我们常说的间隙锁

所以,我在原来文章的基础上补充了两个知识点:

  • 什么是插入意向锁?
  • insert 语句是怎么加锁的?

提纲如下:

d0525758777d9dc25e5800f45be70498.png

正文

有个业务主要逻辑就是新增订单、修改订单、查询订单等操作。然后因为订单是不能重复的,所以当时在新增订单的时候做了幂等性校验,做法就是在新增订单记录之前,先通过 select ... for update 语句查询订单是否存在,如果不存在才插入订单记录。

而正是因为这样的操作,当业务量很大的时候,就可能会出现死锁。

接下来跟大家聊下为什么会发生死锁,以及怎么避免死锁

死锁的发生

本次案例使用存储引擎 Innodb,隔离级别为可重复读(RR)。

接下来,我用实战的方式来带大家看看死锁是怎么发生的。

我建了一张订单表,其中 id 字段为主键索引,order_no 字段普通索引,也就是非唯一索引:

  1. CREATE TABLE `t_order` (
  2. `id` int NOT NULL AUTO_INCREMENT,
  3. `order_no` int DEFAULT NULL,
  4. `create_date` datetime DEFAULT NULL,
  5. PRIMARY KEY (`id`),
  6. KEY `index_order` (`order_no`) USING BTREE
  7. ) ENGINE=InnoDB ;

然后,先 t_order 表里现在已经有了 6 条记录:

ad8e8fb8b9f6ccbec03f1bd9333d018e.png

图片

假设这时有两事务,一个事务要插入订单 1007 ,另外一个事务要插入订单 1008,因为需要对订单做幂等性校验,所以两个事务先要查询该订单是否存在,不存在才插入记录,过程如下:

0f6128083eca2d8dc10cf197827b335d.png

图片

可以看到,两个事务都陷入了等待状态(前提没有打开死锁检测),也就是发生了死锁,因为都在相互等待对方释放锁。

这里在查询记录是否存在的时候,使用了 select ... for update 语句,目的为了防止事务执行的过程中,有其他事务插入了记录,而出现幻读的问题。

如果没有使用 select ... for update 语句,而使用了单纯的 select 语句,如果是两个订单号一样的请求同时进来,就会出现两个重复的订单,有可能出现幻读,如下图:

d1c87a74a09adcd84ba888534024b53d.png

为什么会产生死锁?

可重复读隔离级别下,是存在幻读的问题。

Innodb 引擎为了解决「可重复读」隔离级别下的幻读问题,就引出了 next-key 锁,它是记录锁和间隙锁的组合。

  • Record Loc,记录锁,锁的是记录本身;
  • Gap Lock,间隙锁,锁的就是两个值之间的空隙,以防止其他事务在这个空隙间插入新的数据,从而避免幻读现象。

普通的 select 语句是不会对记录加锁的,因为它是通过 MVCC 的机制实现的快照读,如果要在查询时对记录加行锁,可以使用下面这两个方式:

  1. begin;
  2. //对读取的记录加共享锁
  3. select ... lock in share mode;
  4. commit; //锁释放
  5. begin;
  6. //对读取的记录加排他锁
  7. select ... for update;
  8. commit; //锁释放

行锁的释放时机是在事务提交(commit)后,锁就会被释放,并不是一条语句执行完就释放行锁。

比如,下面事务 A 查询语句会锁住(2, +∞]范围的记录,

发表评论

表情:
评论列表 (有 0 条评论,180人围观)

还没有评论,来说两句吧...

相关阅读

    相关 MySQL 怎么办

    之前分享过 [MySQL 死锁][MySQL]的文章,然后很多读者对「插入意向锁」认识很迷糊。 大家误以为「插入意向锁」是意向锁,也就是表锁,确实这个名字很让人误解。 但是

    相关 MySql

    MySql 死锁 一、什么是死锁 InnoDB存储引擎定义了四种类型的行锁 隔离等级对加锁的影响 当前数据对加锁的影响

    相关 发生怎么办

    > 锁的定义:死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。竞争的资源可以是:锁、网络连接、

    相关 mysql

    1、什么是mysql死锁? 官方定义如下:两个事务都持有对方需要的锁,并且在等待对方释放,并且双方都不会释放自己的锁。 举例:这个就好比你有一个人质,对方有一个人质,你

    相关 MySQL怎么办

    发生表锁的一些原因 1、锁表发生在insert  update 、delete 中    2、锁表的原理是 数据库使用独占式封锁机制,当执行上面的语句时,对表进行锁住

    相关 MySQL

    MySQL 死锁是面试常问问题,金三银四,所以最近面试相关的文章比较多,本文章是总结的一波死锁问题,和大家分享一下,本文参考的博客在文末下方,希望大家可以参考一下。 Mys