数据过长导致重复插入
本该唯一的产品型号字段,在列表中大量出现重复数据,看了看代码,确实是先查库,存在就跳过,匪夷所思。
一、问题描述:
最近部署了一套新的线上环境,项目上线跑了一段时间后,发现产品型号列表中出现了大量重复的型号,代码逻辑也确实是先查库,存在就跳过,手动添加了几条做测试(之前的数据是kafka推送的),又确实不能重复添加。
二、问题排查
拿kafka的数据作对比,发现几条推送时间和数据库创建时间相同的数据,型号竟然不一样,直接按kafka推送的型号搜索也搜不到,几经排查,发现问题:当型号数据长度超出数据库对应字段长度限制时,会被截断为数据库限制的长度并存入,而不是直接报错Data too long for column,这就导致数据过长时,数据库中并没有与之完全相同的数据(都是被截断的),那么就可以重复插入,且插入的都是截取的部分。
三、问题解决
- 通过查资料发现数据库插入数据有严格模式和非严格模式,不同模式数据处理行为不同:
| 数据库 | 典型行为(严格模式) | 典型行为(非严格模式) |
|---|---|---|
| MySQL / MariaDB | 插入失败,报错 1406 - Data too long for column | 静默截断,插入字段对应长度的字符(从开头截取,并产生警告) |
| 达梦 (DM) | 插入失败,报错 “字符串截断” 或 “数据超长” | 静默截断 |
| SQL Server | VARCHAR(32) 定义的是字节数,取决于编码。通常也会失败或截断。 | 同上 |
- 可以使用以下命令检查当前模式:
SELECT @@sql_mode;
如果结果中包含 STRICT_TRANS_TABLES 或 STRICT_ALL_TABLES,则表示严格模式已开启。
- 于是对应的解决方案就有了:
- 对应的值在代码层面添加长度校验;
- 数据库启用严格模式(按需),SET SESSION sql_mode = ‘STRICT_TRANS_TABLES,设置后字段超长插入会直接失败报错。
使用的是华为云的数据库,记得排查!!!