mysql死锁(锁与事务)

匿名 (未验证) 提交于 2019-12-02 22:02:20

线上某服务时不时报出如下异常(大约一天二十多次):“Deadlock found when trying to get lock;”。


1 死锁是怎么被发现的?

1.1 死锁成因&&检测方法

1.2 wait-for graph原理

1.2.1 锁与索引的关系

id: bigint

token: varchar(30)

message: varchar(4096)


1)delete from msg where id=2;

2)delete from msg where token=’ cvs’;

3)delete from msg where message=订单号是多少’;

1.2.2 锁与隔离级别的关系

1)未提交读(Read uncommitted);

2)已提交读(Read committed(RC));

3)可重复读(Repeatable read(RR));

4)可串行化(Serializable)。

我们较常使用的是RC和RR。

RC级别下尽管加了行锁,但还是避免不了幻读。

RR隔离级别可以避免幻读发生,怎么实现?当然需要借助于锁了!

gap锁(间隙锁)

3 死锁成因

3.1不同表相同记录行锁冲突

3.2相同表记录行锁冲突

3.3不同索引锁冲突

3.4 gap锁冲突

4 如何尽可能避免死锁

1)以固定的顺序访问表和行。比如对第2节两个job批量更新的情形,简单方法是对id列表先排序,后执行,这样就避免了交叉等待锁的情形;又比如对于3.1节的情形,将两个事务的sql顺序调整为一致,也能避免死锁。

2)大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。

3)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率。

4)降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁。

5)为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增大。

5 如何定位死锁成因

1)通过应用业务日志定位到问题代码,找到相应的事务对应的sql;

start tran 1 deleteHeartCheckDOByToken 2 updateSessionUser ... commit

2)确定数据库隔离级别。

3)找DBA执行下show InnoDB STATUS看看最近死锁的日志。

  这不就是图10描述的死锁嘛!

start tran 1 updateSessionUser 2 deleteHeartCheckDOByToken ... commit

来源: https://www.cnblogs.com/111testing/p/11371236.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!