查了好几天的问题终于画上了句号

问题背景:

产品接到前方实施反馈9月02日有些订单查不到签名值,对于医院验签查不到签名值,就无法完成验签数据归档。

问题追踪过程:

1 首先查数据库,发现订单id确实查不到对应的detail数据; 第一直觉是否是阿里云dts数据迁移出了问题?因为超过12天数据,由rds数据库迁移到polardb中。

2 和运维确认了dts 14号 任务迁移是成功的。  14号迁移创建时间在9月02日的数据;既然成功的,就断了念想,继续从日志,从代码看能不能找到问题

3 看日志有签名成功的日志,理论上detail会插入数据的。  那是否9月02日有发版?查看spug发布记录,还确实有发版,但发版时间18:00左右,反馈查不到的订单哪个时间段的都有,应该不是发版导致的。

4 这个问题其实中秋节前就反馈的,当时由于其他事情忙着先搁置的,也是由于百思不得其解不想继续死胡同里绕。有时可能洗个澡或者做点儿别的事情放松一下,反而回来才有新的发现。就暂缓继续查了。

5 节后又因为孩子打疫苗,周五下大雨又请了2天假,这个问题一直搁置,同事也没有查出个所以然

6 9月23日 周一产品又在催促,其实没人催促,这个问题也是我自己的心结,莫名奇妙数据就没了么?这多恐怖!

7 然后昨天不知道怎么突然想起来查下总数;查了20240902的归档表的 订单表和详情表的总数,总数是一致的,说明detail数据并没有少啊,然后从反馈问题的时间段查询这个时间段的数据,把id都粘出来,然后vim看下,啊,这是什么东东!傻眼了。这前面都多了个特殊字符 ,至少数据没丢,暂时缓一口气。

查了好几天的问题终于画上了句号_第1张图片

8、网上搜了下这个特殊字符,说是utf-16编码的标识。随即就到迁移的目标库里detail表果然是utf-16字符编码,那这个特殊字符就是因为改了utf-16导致的呗,在从9月02日日期再往前确认,8月29日就改了这个编码。查了下订单,果然8月29日之后都查不到(这个运维之前反馈阿里云dts数据迁移失败,说是字符集不一致导致的失败,但当时没仔细确认,谁知道运维自己改了目标表的字符集utf16,但2个原表其实是utf8编码和utf8mb4),改了字符集迁移任务确实没报错了,但把数据格式搞乱了。

9、数据错了,首先想着怎么程序兼容能查到这个数据,毕竟恢复数据比较慢,10天左右的数据,每天一个表,单张表1000w左右;
但程序上兼容,在这个上面也花费了好长时间。分别尝试了以下几种都查不到数据,

//                String cmd = "SELECT * FROM  tms_history.`doctor_sign_detail_20240902` where sign_id = 'Y17252583253809c8518bface5e07b3'";//不行
//                String cmd = "SELECT * FROM  tms_history.`doctor_sign_detail_20240902` where sign_id = '\uFEFFY17252583253809c8518bface5e07b3'";//不行
//                String cmd = "SELECT * FROM  tms_history.`doctor_sign_detail_20240902` where sign_id='Y17252583253809c8518bface5e07b3'";不行


//                String cmd = "SELECT * FROM  tms_history.`doctor_sign_detail_20240902` where sign_id='Y17252583253809c8518bface5e07b3'";//不行

那这个特殊字符在java程序里到底如何表达呢?还因此向阿里云工程师提了工单,对方也没有很好的兼容方式。最后一位老大说用mysql的convert函数试试       

where columnname = convert(str using utf16)         好像起作用了!(其实后来证实也没起作用)

然后改代码兼容,但测试的时候发现如果不是utf16的字段会报错,8月29日之前的就会查询报错吧,还需要分时间段去兼容下!问题怎么越改越多!

不知不觉又到了晚上快9点,实在皮了眼睛也花了,大boss还人文关怀了下,说***下班吧。先下班吧,修正一下,大不了明早早到公司早早改好。

10、今天早上到公司才发现,昨天的convert也不起作用,可能昨天拷贝来拷贝去,有的带了特殊字符的(肉眼不可见)就能查到,普通的utf8字符串id还是查不到。那如何兼容?早上让同事也查一下确认下,同事说你给我的id是31位的,为什么呢?原来字段长度设置的是32,前面多了个不可见的特殊字符,最后一位就被截取了;原来之前程序里兼容查不到是因为id一直少1位匹配不上。

11 来到了最终解决方案:对于特殊时间段(用了utf16编码的)改like查询。

String cmd = "SELECT * FROM  tms_history.`doctor_sign_detail_20240902` where sign_id like '\uFEFFY17252583253809c8518bface5e07b3%'"; //生效了!!

得亏这个id缺失的是最后一位,还能用like 右模糊查询,索引还生效着!

     且查询结果有些字段也是缺少一位(都是因为表是utf16编码,所有字段未单独指定字符集就用了表的字符集,且字段长度都是32位,因特殊字符都少了最后一位)

      但这个前提是自己自定义的sql 直接 like '****%'。而下面这种用mybatisplus的like语句,实际查询sql变成了  like %certId%% 并没有走索引,导致慢sql (今天从cat监控上发现的,如下图)。

既然like是左右都加了%,那一定还有只加左或只加右的匹配,果然如自己猜想那样,还有likeLeft和right。然后网上搜了likeLeft和likeRight的区别,实际上很多描述返的。自己先用likeLeft测了一下,在dev环境看下sql日志输出,但却发现开发环境日志里没有输出sql语句,按说是debug级别应该能看到日志的。搜了网上如何开启mybatisplus日志,很多都没有用,改了配置依然看不到日志!后来阴差阳错的看到一篇又折腾修改一下,好像有用了!(文章后面会解释其实不是配置问题看不到日志

改完日志配置后,在dev环境日志果然看到sql语句了,但likeLeft在左边加了模糊%,和网上很多描述的不一致,所以没有实践就没有发言权,网上有些东西容易误导人,最好是自己验证下!!

likeLeft 是%在左边,也就是模糊在左边,相当于查询的是以某个关键字结尾的!

最终是需要使用mybatisPlus的likeRight实现查询以某个字符串开头的!

其实后来在看sql日志,发现一个问题,又看不到日志了!原来之前看不到日志并不是配置问题,而是因为查询的方法上加了@Cacheable注解,缓存有效的情况下,不会走到方法体里,也就不会打印sql语句了!

查了好几天的问题终于画上了句号_第2张图片

至此困扰多日的问题终于解决了,晚上可以睡个安稳觉了。

再将运维的迁移脚本创建表确认下,居然目标表创建了很多索引,按说迁移到历史polardb后数据就不会频繁根据条件查询,顶多根据主键查询,所以dts迁移数据任务也一并优化了下,建表去除不必要的索引,detail表的编码由utf16改为utf8mb4 (经过测试可兼容utf8mb4和utf8的迁移,且数据没有增加意外的字符)!

你可能感兴趣的:(java,mybatis)