Mysql隐式转换带来的生产问题
问题场景:
JDK1.8 + Mysql 5.7 + RocketMq
最近上线一个项目,上线之后看日志发现程序不断的报错"Lock wait timeout exceeded; try restarting transaction"(事务回滚异常,等待超时).一开始一脸懵逼,之前完全没遇到过这种错误.于是,马上开始查看出错的生产库数据是否正确. 查看了一番后,部分数据正常,部分数据缺失了.后来大概23:00左右,这种错误慢慢的少了...作为萌新,询问了组内大佬,组内大佬给的解释是 代码的sql里面使用了 replace into语法,这是一个间隙锁,导致了锁表异常.
由于当晚没有再出现这种情况,暂时没有解决,等到第二天再看看.
第二天一到公司.,打开日志发现又不断的出现了该现象"Lock wait timeout exceeded; try restarting transaction", 因为没有碰到过,查了很多资料,还是不知道如何解决. 突然此时DBA找了过来,说数据库cpu飙升90%,一说可能使我们的代码导致的,于是...
问题分析:
前面问题的场景当然只是作为一个萌新的无助,不知道如何去排查. 首先出现该问题的原因是由于数据库锁表了,高并发的DML(update)操作,导致后一个DML操作处于等待重试状态,大量的操作处于等待之中,导致数据库cpu飙升.
找到这个宏观的原因之后,接着查看自己的代码问题,锁定问题为一个update语句导致的,update(Obj obj),这个表的主键是mobile,类型为varchar ,但是我们自己定义的实体类对象的类型为 Long . 由此可以判断此处发生了隐式转换,导致update语句没有使用到主键索引,扫描了全表.这张表的数据大概是 280w,可想而知,每个操作做基本遍历一次,导致大范围锁表. 当然这是前人留下的坑...,实体类的定义以及表的建立都是前人的结果~.
解决方法:
这个update语句的使用场景为消费登录MQ消息,处理业务逻辑,所以在DBA发现了这个问题之后,马上下线了这个消费者(代码注释上线),暂停消费 . 找到问题后,再将这个实体类的类型替换为String,再次消费登录消息,进行业务处理,至此程序正常,没有在出现锁表异常.
扩展资料:
带着上线的问题,那我们来了解下一下问题:
1.什么是隐式转换(显示转换)?
2.replace into是个什么玩意?
3.数据库的锁?
问题1:
默认的转换规则为:
不同类型全部都转换为浮点型
如果字段是字符,条件是整型,那么会把表中的字段全部转换为整型。
问题2:
replace into 跟 insert 功能类似,不同点在于:replace into 首先尝试插入数据到表中,
-
如果发现表中已经有此行数据(根据主键或者唯一索引判断)则先删除此行数据,然后插入新的数据。
-
否则,直接插入新数据。