数据库表字段值设置太短导致的现网问题

故事背景

在一个休闲的周末,突然看到工作群里传来信息:智能运维告警报错了几十条,麻烦看看什么原因。我一看是支付网关报错:----com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'data' at row 1。感觉麻烦了,因为前两天刚上了新版本,可能是新版本的改动导致这个问题,还是支付回调流程报的错- -赶紧打开VPN看一下什么原因。

问题分析

打开服务器查看日志,发现告警是在早上6点到6点08分的时间出现,只是支付宝的自动续费流程出现了,普通下单和微信支付都没有出现。再观察一下有没有正常回调给合作方,如果没有的话那就是用户买了会员但是没发权益,会产生客诉。我都准备写程序手动调一下回调接口,后面看到程序在捕捉异常后也有调用HTTP请求通知合作方,业务流程没问题,我也没这么紧张了。

从上面的业务流程图中可以发现,是最后的更新重试参数data存入数据库时报错,新版本的一个改动是回调参数添加了userId,data的值:{"seqno":"xxx","traceno":"xxx",msg:"xxx" .....} 。因为初始版本的回调参数大约只有100+字符左右,所以默认用了255字符串长度,后面回调参数越加越多,255就不够用了。

组合技

奇怪的是之前这个版本测试了挺久也没有发现这个问题,上线之后才暴露出来。后面分析后才发现是要三种情况的组合技同时满足才能触发该问题。

1、由于正向的下单请求还没执行完保存入库,支付宝就开始发起回调,导致订单查询失败,返回支付网关重试,才会写入重试的参数data。为什么会还没保存入库,因为下单请求是执行完HTTP请求之后再入库,如果HTTP请求还没执行完,回调就过来了,就会出现这种情况,只能说支付宝回调速度太快了- -

2、需要是支付宝的自动续费流程,如果是普通下单流程,是返回了预下单地址,这时候肯定是执行入库完了,用户扫码支付后才会支付回调,所以不会出现问题。微信的自动续费支付回调也没有支付宝速度这么快。

3、userId有长有短,如果短的话是刚好250字符左右,长的话就会超出255报错了。

所以是这三个组合技下来导致现网早晨6点的自动续费时间会报数据库插入报错。

修改字段长度

修复上面的bug就是修改字段长度,最关键的是看数据库改动会不会锁表,如果锁表就会影响业务流程。这个之前已经测试过了。分几种情况:

编码utf8:

50改成60 不锁表

50改成70 锁表

255改成1000 不缩表

分界线 256/3 ≈ 85字节,如果跨越了85字符就会锁表

同理 utf8-mb4 256/4 = 64,以64字符为分界线

大改小 锁表

要扫描所有字段是否符合长度

SQL执行:

alter table xxx modify column data varchar(1000);

因为不会锁表,所以可以直接执行。为了防止锁表,准备另外的页面查询正在执行的SQL,把它kill掉

SELECT * FROM information_schema.processlist WHERE command != 'Sleep';

总结

设计数据库字段的时候一定要好好考虑长度问题,问了一下其他朋友,都有试过这种长度设置不够的情况,最好是预留长一点,如果未来业务拓展会导致字段越来越长,就要设置1000长度左右,之前有一个QUA字段也是封装了多个参数,后面也试过报了插入字段太长。

另外支付回调一定要通知到合作方!还好catch里面发送了HTTP请求,不然问题比较严重,虽然合作方也做了兜底逻辑:没收到支付回调会过一段时间调用我们查询接口查询订单是否支付。

相关推荐
free-9d1 小时前
NodeJs后端常用三方库汇总
后端·node.js
Dcs1 小时前
用不到 1000 行 Go 实现 BaaS,Pennybase 是怎么做到的?
java
Cyanto3 小时前
Spring注解IoC与JUnit整合实战
java·开发语言·spring·mybatis
qq_433888933 小时前
Junit多线程的坑
java·spring·junit
gadiaola3 小时前
【SSM面试篇】Spring、SpringMVC、SpringBoot、Mybatis高频八股汇总
java·spring boot·spring·面试·mybatis
写不出来就跑路3 小时前
WebClient与HTTPInterface远程调用对比
java·开发语言·后端·spring·springboot
Cyanto3 小时前
深入MyBatis:CRUD操作与高级查询实战
java·数据库·mybatis
麦兜*4 小时前
Spring Boot 集成Reactive Web 性能优化全栈技术方案,包含底层原理、压测方法论、参数调优
java·前端·spring boot·spring·spring cloud·性能优化·maven
天上掉下来个程小白4 小时前
MybatisPlus-06.核心功能-自定义SQL
java·spring boot·后端·sql·微服务·mybatisplus
知了一笑4 小时前
独立开发第二周:构建、执行、规划
java·前端·后端