细节就是魔鬼--记一次sql动态拼接逗号引起的线上异常
文章目录
线上问题无大小,只要有隐患,出现了就是大问题。细节就是魔鬼。
细节就是魔鬼,今天真实的体验了一次什么叫做惊弓之鸟。
新上的需求今天开始放量,从放量开始的半小时左右开始出现大量的告警,这是很不寻常的。查看ELK告警信息,发现是sql-parser异常。我很惊讶,按道理这种问题是不应该出现的,但是线上问题无小事。
于是截取了一段日志如下,(消除了敏感信息)
Caused by: java.util.concurrent.ExecutionException: com.xxxx.sql.parser.SQLParserException: syntax error, expect RPAREN, actual IDENTIFIER url
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at com.alipay.zdal.parser.DefaultSQLParser.getStatement(DefaultSQLParser.java:177)
... 68 more
Caused by: com.xxxx.sql.parser.SQLParserException: syntax error, expect RPAREN, actual IDENTIFIER url
at com.alipay.zdal.parser.sql.parser.SQLParser.accept(SQLParser.java:136)
at com.alipay.zdal.parser.sql.dialect.mysql.parser.MySqlStatementParser.parseInsert(MySqlStatementParser.java:1774)
异常堆栈很清晰的指出问题所在:url字段处存在sql异常。
于是我找到这个版本的代码中该功能执行的sql,如下:(sql字段已经脱敏)
INSERT INTO table (
aaaa,
bbbb,
cccc,
dddd
<isNotEmpty property="uid">
,uid
</isNotEmpty>
<isNotEmpty property="nickname">
,nickname,
</isNotEmpty>
<isNotEmpty property="url">
url
</isNotEmpty>
,userid,
好了,问题找到了,下面这行的值没有传递,导致sql解析器解析到逗号的缺失。实际运行的sql变成了
INSERT INTO table (
aaaa,
bbbb,
cccc,
dddd,
uid url,
userid,
这样sql解析就出错了。
所幸没有出现大问题,但是还是给各位同事带来了麻烦,让大家又额外的经历一次上线的流程。
总的来说,还是个人的原因导致的,不需要找客观原因。核心就在于,开发阶段测试用例覆盖率没有做好,非空判断依赖了数据库的动态SQL。
发现问题就要解决,及时止损,解决完问题要时刻反思进步。今天的事情给我的启示是:
- 上线前打TAG,对于上线完成的分支要做到留存,合并到主干后,待主干回归完成再删除。
- 开发阶段测试用例尽量覆盖到,这个我也做的不够好,只关注了正常的情况,对于边缘的情况一定要尽量覆盖到。对于测试同学提出的bug要及时跟进。
- 不要相信代码评审的结果,也就是不要相信他人,可以参考他人的意见,一切以测试用例执行情况为准。
- 对于sql而言,不要依赖sql本身的非空判断,出现问题不好复现,而且一旦出现线上问题,大多数人都不会太冷静,你更不会。对于空值的处理尽量在业务逻辑处理。
时刻牢记,细节就是魔鬼,线上问题无小事。