最近在业务代码上遇到一个mysql update死锁问题,纠结了2天,尝试了各种方式,最终特别用特别简单的方法解决了,记录一下
业务场景描述一下
是两个客户端之间通过中心进行报文收发处理,发报端进行发报,记录该报文进发报表,并且实时更新该报文状态(记住这里);
中心收到报文,转发至收报端,收报端对报文进行处理,返回应答报文;
中心将应答报文转发至发报端,发报端收到应答,根据应答报文,更新原报文状态;一套业务处理结束。
当场景是单线程时,并不会出现问题,但是一旦出现多线程,高并发的情况下,就会因为发报端发报和收到应答报文之间间隔不足1ms,update同一条报文,而产生死锁,这里是行级锁,我用的update是通过三个字段唯一锁定一条数据,但这三个字段不是联合主键,也没有索引;
我万事求百度,百度告诉我,非主键索引和主键索引会先锁定非主键索引,再锁定主键索引,但我没有,所以我最初的解决方式是,先根据这三个字段取到主键,再根据主键update数据,这时就不存在行级锁。
但是新的问题出现了,当发报端,收到高并发的不同的应答报文时,再去update原数据,会出现根据这三个字段查询一条数据,但是因为这三个字段并非索引,就会产生锁表的情况。这时直接表级锁,所有后面的update全部等待,直至死锁。这个时候的解决办法就是,在原来的基础上把这三个字段加多列索引,至此问题解决。
问题解决的时候发现如果一开始就加索引的话,可能只会遇到行级锁,这次也算小小收获。还有一点,代码里面是有事务处理的,但事务在这里并没有影响。