本文主要从共享锁(S锁)和独占锁(X锁)出发,详细说明两种锁的加锁机制,以及死锁如何产生。mysql
上一篇文章中咱们已经讲解了共享锁和独占锁的基本概念,我这边再详细将一下。sql
共享锁。
S锁 | X锁 | |
---|---|---|
S锁 | 兼容 | 不兼容 |
X锁 | 不兼容 | 不兼容 |
了解了S锁和X锁,那么咱们来看看什么是死锁吧。
让咱们来复现下死锁的过程,以便更好理解。建议能够根据本身理解来复现死锁过程,并分析缘由加深理解。否则变成:
眼睛: 我会了。
脑子: 不,你不会。数据库
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`age` int(11) NOT NULL,
`addresss` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT student VALUES (1,'张一',12,'ssss'),(2,'张二',12,'ssss'),(3,'张三',12,'ssss'),(4,'张四',12,'ssss'),(5,'张五',12,'ssss');
复制代码
准备工做完成,创建表,并插入5条数据。并发
模拟死锁第一步
新建一个数据库链接并执行:高并发
###事务A
begin;
select * from student where id in (1,2) lock in share mode;
复制代码
步骤一 事务A 获得了id 为1,2的S锁。
再新建一个数据库链接并执行:ui
###事务B
begin;
select * from student where id in (1,3) lock in share mode;
复制代码
步骤二 这时事务B 获得了id为1,3的S锁
而后咱们在事务B 中尝试
获取数据id = 2 的X锁spa
事务B
update student set age =100 where id = 2
复制代码
步骤三, 因为id为2 被事务A加了S锁,因此事务B 被阻塞。
最后咱们在事务A中尝试获取数据id = 3 的X锁rest
事务A
update student set age =100 where id = 3
#执行结果:1213 - Deadlock found when trying to get lock; try restarting transaction, Time: 0.005000s
复制代码
步骤四,因为id为3 被事务B加了S锁,因此事务A被阻塞。 固然其实执行的时候被跳出死锁警告。事务A回滚撤销了。
code
到此,咱们模拟了整个死锁过程,因为B 为了得到X锁须要等A执行完成,而A后续反而为了得到X锁须要等B执行完成。因此形成了死锁。事务
从上面的例子中咱们能够看到死锁的缘由是相互寻求各自手上的资源(即锁)致使的。
可是其中有个重要的特性
须要说明就是二阶段锁协议
。
二阶段锁协议很简单:
上面例子中步骤三,B之因此会被阻塞,是由于事务A虽然读取数据结束了,可是事务还没结束,因此致使读取是加的锁没有释放。
也是因为二阶段锁协议的缘由,因此咱们应该尽量避免长事务。由于`事务执行时间越长,加锁的时间越长,发生死锁的几率越大```
mysql 能够设置两种处理方式:
通常状况下,咱们会用第一种方式。
现实场景中有哪些容易发生死锁的场景呢?其中最多见的一个例子是减库存了。
扣减库存咱们通常有如下步骤
假设流程的sql语句以下
# 查询剩余库存
select last_number from stock where id = 1000 lock in share mode;
#库存足够 --减去库存
update stock set last_number = last_number - 1 where id = 1000;
复制代码
那么问题是:
问题答案下篇文章回答。有收获,请关注下吧。