行锁、表锁、间隙锁、死锁

2020-01-07  本文已影响0人  阔阔飞翔

一、行锁、表锁、间隙锁说明

https://blog.csdn.net/fy_java1995/article/details/83445201

重点:

当选中某一行时,如果是通过主键或者索引选中的,这个时候是行级锁;如果是通过其它条件选中的,这个时候行级锁会升级成表锁,其它事务无法对当前表进行更新或插入操作

二、MySQL死锁

死锁是指两个或两个以上事务在执行过程中因争抢锁资源而造成的互相等待的现象。

三、发生死锁的3个条件:

1、>= 2个事务

2、不同方向

3、相同锁资源

解决死锁的方法

超时等待:即当两个事务互相等待时,当一个事务等待时间超过设置的阈值时,就将其回滚,另外事务继续进行。(缺点:如果回滚的事务更新了很多行,占用了较多的undo log,那么在回滚的时候花费的时间比另外一个正常执行的事务花费的时间可能还要多,就不太合适);

wait-for graph(等待图):死锁碰撞检测,是一种较为主动的死锁检测机制,要求数据库保存锁的信息链表和事务等待链表两部分信息,通过这两个部分信息构造出一张图,在每个事务请求锁并发生等待时都会判断是否存在回路,如果在图中检测到回路,就表明有死锁产生,这时候InnoDB存储引擎会选择回滚undo量最小的事务。

事务1中的SQL 1语句:

UPDATE  Table_1  SET  LockStatus = 1  WHERE  OrderId = 2233445566  AND BizId =2233445566  AND ActionType = 503   AND LockStatus = 0

根据LockStatus索引更新LockStatus值,对LockStatus索引加上排他锁。

事务2中的SQL 2语句:

UPDATE   Table_1  SET   Status =  4   WHERE   Id =543090

根据主键ID去更新表Table_1中的Status状态,这个时候会对主键索引ID加上排他锁。

原因分析:因为事务1和事务2都是行锁,互不影响运行,这时以LockStatus = 0为查询条件时,可能包含了id=543090这个条件的数据,导致两个事务互相持有对方的锁,锁得不到释放,造成死锁。

产生死锁的原因是第一条SQL语句用到的索引区分度不高,只用到了lockstatsu索引,导致5万条行记录被锁,因此解决方案就是要用区分度更高的索引,根据第一条SQL建立唯一键引:

UNIQUE KEY `UK_OrderId_BizId_ActionType` (`OrderId`,`BizId`,`ActionType`)

上一篇 下一篇

猜你喜欢

热点阅读