Mysql死锁场景总结 (引擎:innodb隔离级别:RR)

概述

死锁:死锁一般是事务相互等待对方资源,最后形成环路造成的。

 

此种场景常见于Springmvc模式中,把事务交由spring管理的场景。这种模式下,由于业务的比较复杂,会导致一个事务内会有多次和数据库进行通信的机会,导致事务一直没提交,产生大事务。

下面具体分析几类在工作中遇到过的死锁场景,主要介绍单表场景,死锁在多表场景中也有,可以按单表的思路进行分析。

死锁场景

一、update的记录顺序不一致

此种情况常见于一个update语句被许多地方共用的场景。

事务一:

Update table set status= #{value} where id in (1,2,3,7,8);

事务二:

Update table set status= #{value} where id in (9,10,3,5);

事务一:

Update table set status= #{value} where id in (1,2,6,7,8);

事务二:

Update table set status= #{value} where id = 5;

Where:后面我这是为了方便列举了id(此处的id并非是主键)的情况,实际业务中还有其他的场景,需要具体分析。

这个写法并不是说一定会发生死锁,是有发生死锁的概率。

二、同一个表中,唯一索引update

Table:business

id  bigint(20) 主键,自增

business_no bigint(20) 不为空,唯一索引(uniq_idx_business_no)

name varchar(50) 不为空

事务中的sql语句如下:

Insert into business(name) values(#{name});

Update business set business_no = #{id} where id = #{id};

  
第一组事务: 

每一个事务按正常的顺序执行完成后,commit是没问题的。(并发量小或没有的时候) 

第二组事务:

 事务一  事务二
SQLInsert into business(name) values(#{name});  Insert into business(name) values(#{name});
已有锁 

RECORD LOCKS space id 27 page no 26 n bits 824 index ` uniq_idx_business_no ` of table `business` 

trx id 19268290 lock mode S locks gap before rec Record lock

等待锁

RECORD LOCKS space id 27 page no 26 n bits 824 index ` uniq_idx_business_no ` of table `business` trx id 

19268220 lock_mode X locks gap before rec insert intention waiting

 
Record lock 

RECORD LOCKS space id 27 page no 26 n bits 824 index `uniq_idx_business_no` of table ` business` 

trx id 19268290 lock_mode X locks gap before rec insert intention waiting 

  

事务一:已经持有间隙锁(gap+X),再等待插入意向锁(insert intention);

事务二:持有行锁(S),在申请获得间隙锁(gap+X)的时候,需要先申请意向锁(insert intention);

死锁发生后,根据事务的权重,有数据库决定回滚哪一个事务来解决死锁问题。

三、普通索引

普通索引这类和顺序不一致的场景有相似处。

Table:match_info

Id  bigint(20)  自增

no bigint(20) Idx_no

code varchar(50)

……    ……

事务死锁场景

 事务一事务二
SqlUPDATE match_info set type = 1 WHERE no = 1644100 AND code = 'CD275019634'

UPDATE match_info set type = 1

WHERE no = 1644100 AND code =  'CD275046788'

等待授权锁 

RECORD LOCKS space id 48 page no 18862 n bits 824 index `idx _no` of table `match_info`

 trx id 188167021 lock_mode X waiting Record lock;

已持有 锁

RECORD LOCKS space id 48 page no 20127 n bits 104 index `PRIMARY` of table ` match_info`

 trx id 188167023 lock_mode X locks rec but not gap waiting Record lock;

 

 

猜想:index `PRIMARY` of table ` match_info`

RECORD LOCKS space id 48 page no 18862 n bits 824 index `idx _no` of table ` match_info` trx id 188167023 lock_mode X Record lock;

对事务一持有的锁的猜想对么?(最后给出答案)

对应的数据记录:

idnocode
1000112231644100CD275019345
1000112241644100CD275019634
100011225

1644100

CD275046322
1000112261644100CD275046788
1000112271644100CD275077643

 

注意,普通索引和主键索引的关系:

         innodb对于主键使用了聚簇索引,这是一种数据存储方式,表数据是和主键一起存储,主键索引的叶结点存储行数据。对于普通索引,其叶子节点存储的是主键值。 

总结:

Update的时候,尽量按主键,一次更新一条;如果确实需要批量,则保证好每次更新的顺序是一致的。尽量保证小事务,使得事务尽快commit。 

问题解答: 
  在普通索引里,对事务一已有的锁的猜想可能是对的,也可能是错的(原因:可能还有其他的事务持有该锁,而并不一定是事务一持有),也或许事务一目前还没有持有任何锁。 

原文引用:http://qhxn-328-liaozx.blog.163.com/blog/static/8760673201762043235983

时间:2017-07-20 16:39:56

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值