并发操作导致的BUG-解决方案
一、问题由来
上周五项目发布新版本之后,生产环境一直没有出现什么问题,大家也都开开心心,平平安安的开始新需求的开发。
可是刚稳定运行没几天,负责人突然在群里面发了一个截图,从图片中的信息可以看到,有一个SQL语句报错。这就不
太好了,这才上线没多久呢,就出这样的问题,不是太好。既然已经出现问题,我们就需要去解决问题,修复BUG。
二、问题分析
从图片中的错误信息来看,报错的SQL语句是一个新增的操作,报错的原因一目了然,唯一索引冲突。这就尴尬了,
怎么会出现这种问题呢?某张表中的某几个字段建立了唯一组合索引,这是最后一道屏障,用来确保表中不出现业务上
重复的数据。在表的设计上这样处理,也算是一个兜底操作,前面的一大波操作都没有起效果,最后一步还是拦住了。
从这个角度来说,这也算是一件好事,如果这一步都没有拦住,那就真的是很尴尬的事情,说明整个设计存在问题。自己
仔细去排查报错的地方,代码不是自己写的,可是也需要一起进行排查,毕竟大家都是同一个项目组的,有问题大家一起
解决,总比自己单打独斗强。现在帮忙排查问题,以后自己遇到问题了,相信同事也会出手相助的。
经过仔细排查,发现在同步某个MQ信息的时候,在判断某条数据是否重复的时候出现问题,判断的方式为先根据几个
字段查询某条数据是否存在,这几个字段就是上面创建唯一组合索引的字段。如果存在则进行更新操作,如果不存在则
进行新增操作。并且在执行这个方法之前,还是使用了redis锁操作。锁的方法很复杂自己看了大半天都没看懂,很
长一段代码。其他地方使用redis锁的代码是没问题的,自己之前测试的时候,亲自遇到过,会不会是加锁的方式不对呢?
经过和同事的讨论,最终确认是加锁的方式不对导致的问题,由于刚好不巧,多条数据通过MQ过来的时候,消费数据时
导致出现问题。
三、解决方案
既然问题已经找到了,那么如何解决问题呢?第一种解决方案是,修改redis加锁的key,这个key必须要包含上面建立
唯一组合索引的几个字段,这样才能够真正的锁住代码,不然锁就会失效。负责人了解到我们排查到问题后,给出了另外一个
解决方案,那就是将新增操作和修改操作抽取为一个SQL语句,语句中判断条件就是创建的唯一组合索引,这样就很好的解决了
并发修改问题。由于使用的postgresql,可以做这种操作,mysql不知道有没有同样的操作。修改好代码后,立即反反复复地
进行测试,都未在出现相同的问题,因此判定这个并发修改问题已经解决。有其他思路的小伙伴,欢迎留言讨论。