mysql死锁专题
2021-02-23 22:28:16 0 举报
AI智能生成
mysql死锁
作者其他创作
大纲/内容
锁的级别
表级锁
开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁
开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁
开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
算法
Gap锁
不锁记录,仅仅记录前面的Gap
Recordlock锁
锁数据,不锁Gap
next KeyLocks锁
同时锁住记录(数据),并且锁住记录前面的Gap
对于行的查询,都是采用该方法,主要目的是解决幻读的问题
加锁分析
SQL1:select * from t1 where id = 10;
SQL2:delete from t1 where id = 10;
SQL2:delete from t1 where id = 10;
RC,RR隔离级别下
SQL1:select操作均不加锁,采用的是快照读
SQL2加锁分析
id主键+RC
id是主键时,此SQL只需要在id=10这条记录上加X锁即可
id唯一索引+RC
若id列是unique列,其上有unique索引。那么SQL需要加两个X锁,一个对应于id unique索引上的id = 10的记录,
另一把锁对应于聚簇索引上的[name='d',id=10]的记录
另一把锁对应于聚簇索引上的[name='d',id=10]的记录
id非唯一索引+RC
若id列上有非唯一索引,那么对应的所有满足SQL查询条件的记录,都会被加锁。
同时,这些记录在主键索引上的记录,也会被加锁
同时,这些记录在主键索引上的记录,也会被加锁
id无索引+RC
若id列上没有索引,SQL会走聚簇索引的全扫描进行过滤,由于过滤是由MySQL Server层面进行的。因此每条记录,无论是否满足条件,都会被加上X锁。但是,为了效率考量,MySQL做了优化,对于不满足条件的记录,会在判断后放锁,最终持有的,是满足条件的记录上的锁,但是不满足条件的记录上的加锁/放锁动作不会省略。
id主键+RR
id是主键时,此SQL只需要在id=10这条记录上加X锁即可
id唯一索引+RR
若id列是unique列,其上有unique索引。那么SQL需要加两个X锁,一个对应于id unique索引上的id = 10的记录,
另一把锁对应于聚簇索引上的[name='d',id=10]的记录
另一把锁对应于聚簇索引上的[name='d',id=10]的记录
id非唯一索引+RR
Repeatable Read隔离级别,防止缓读,需要加Gap锁
所谓幻读,就是同一个事务,连续做两次当前读 (例如:select * from t1 where id = 10 for update;),那么这两次当前读返回的是完全相同的记录 (记录数量一致,记录本身也一致),第二次的当前读,不会比第一次返回更多的记录 (幻象)
Gap锁作用:第一次当前读与第二次当前读之间,其他的事务不会插入新的满足条件的记录并提交
主键和唯一索引,都能够保证唯一性。一个等值查询,最多只能返回一条记录,而且新的相同取值的记录,一定不会在新插入进来,因此也就避免了GAP锁的使用
d列上有一个非唯一索引,对应SQL:delete from t1 where id = 10; 首先,通过id索引定位到第一条满足查询条件的记录,加记录上的X锁,加GAP上的GAP锁,然后加主键聚簇索引上的记录X锁,然后返回;然后读取下一条,重复进行。直至进行到第一条不满足条件的记录[11,f],此时,不需要加记录X锁,但是仍旧需要加GAP锁,最后返回结束
id无索引+RR
在Repeatable Read隔离级别下,如果进行全表扫描的当前读,那么会锁上表中的所有记录,同时会锁上聚簇索引内的所有GAP,杜绝所有的并发 更新/删除/插入 操作。当然,也可以通过触发semi-consistent read,来缓解加锁开销与并发影响,但是semi-consistent read本身也会带来其他问题,不建议使用。
Serializable
MySQL/InnoDB中,所谓的读不加锁,并不适用于所有的情况,而是隔离级别相关的。Serializable隔离级别,读不加锁就不再成立,所有的读操作,都是当前读。
死锁产生的原因
两个(或以上)的Session加锁的顺序不一致
两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB
案例
案例一
in里面的列表值mysql是会自动从小到大排序,加锁也是一条条从小到大加的锁
案例二
当对存在的行进行锁的时候(主键),mysql就只有行锁
当对未存在的行进行锁的时候(即使条件为主键),mysql是会锁住一段范围(有gap锁)
案例三
两个session分别通过一个sql持有一把锁,然后互相访问对方加锁的数据产生死锁
案例四
两个单条的sql语句涉及到的加锁数据相同,但是加锁顺序不同,导致了死锁
0 条评论
下一页