MySQL 会发生死锁吗?(转)

本贴最后更新于 1820 天前,其中的信息可能已经斗转星移

MySQL 的 InnoDB 引擎事务有 4 种隔离级别,主要是为了保证数据的一致性。

InnoDB 引擎提供了行级锁,表锁。MyISAM 提供了表锁,如题,MySQL 会发生死锁吗?

会,在 InnoDB 引擎下,RR(REPEATABLE-READ)级别,如果多个事务争抢同一个资源,会发生死锁。在 RR 级别下,MySQL 提供了 next-key lock。假如一个索引的行有 10,11,13,20
那么可能的 next-key lock 的包括:
(无穷小, 10]
(10,11]
(11,13]
(13,20]
(20, 无穷大)

即:当你查询 12 时,如果数据未查到,那么将对(12,13]范围内的数据进行锁定。next-key lock 的定义可以到官方具体查看,这里做个演示。

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(200) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1111 DEFAULT CHARSET=utf8;

426671f9b1689716bdbf68.jpg

//查看隔离级别,
show variables like '%tx_isolation%';
// 设置隔离界别
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
// 不设置自动提交
SET autocommit = 0;

死锁演示

  1. 首先将隔离级别都设置为 RR 级别的,并且不让事务自动提交
  2. 根据上面的数据,在事务 1 中查询
// 得到空结果集,此时锁定的范围是(33,100]
select * FROM user where id=33 for update;

  1. 在事务 2 中也进行查询
// 查询到空的结果,在事务2中锁定的范围是(34,100]
select * FROM user where id=34 for update

  1. 在事务 1 中插入数据
// 虽然事务1锁定了范围,事务2也锁定了范围
insert into user values(35,'ac',10);

  1. 在事务 2 中也插入数据
insert into user values(34,'ac',10)

  1. 可以发现已经发生了死锁

解决办法

  1. 设置死锁的超时时长

innodb_lock_wait_timeout=500

  1. 查询到当前正在锁定的事务线程,将其杀死
// 可以看到正在运行的事务线程,还有运行状态
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

//trx_mysql_thread_id为上一条命令获取的结果,将具体的数字替换一下即可。
kill trx_mysql_thread_id

作者:Real_man
链接:https://www.jianshu.com/p/556613501866
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • MySQL

    MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是最流行的关系型数据库管理系统之一。

    677 引用 • 535 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...