这几天,在搞 ShardingSphere,这不又来了一个问题嘛,启动的时候报了一个NPE出来。


可恶,又是个线上问题!_mysql

好在,这个问题不影响使用,只是启动会报点错,接下来,又是辛苦的排查过程。

直接定位到报错的地方,发现是ShardingSphere在启动时候去加载表一些元数据信息报错,看到这个地方就很明显的猜测是 map 去 get 的时候报错了。


可恶,又是个线上问题!_mysql_02

一通往上翻源码,发现这里定义的是 TreeMap,那应该没毛病了,就是上面 dataType 是个 null,所以报错了,可是我还是年轻了。


可恶,又是个线上问题!_mysql_03

问题原因

上面我们已经定位到问题出现的地方,接下来就分析下为什么会出现这个问题呢?

从源码看到,主要是在这个地方去加载数据库表的列的元数据信息。


可恶,又是个线上问题!_java_04

在这个类里发现了拼接的 SQL 查询语句,主要是去查 information_schema 下面的 columns 表。


可恶,又是个线上问题!_mysql_05

这时候我想看下这个到底是为啥,于是打开本地 debug 看了一下没有任何问题,然后去测试环境上发现也没有问题,好像只有生产有这个问题。

这个 dataTypeMap 就是列类型的一个映射,但是本地没有办法重现。


可恶,又是个线上问题!_spring_06

本地没有办法的话,那就根据上面的 SQL 去生产库里看了下 COLUMNS 表这个字段有啥问题,查询一看,发现了一大堆的 null,还有一些其他的乱七八糟的类型,那看来 NPE 的原因就是因为这些 null 了。


可恶,又是个线上问题!_数据库_07

那这些 null 值是怎么来的呢?根据排查发现都是来自 TIDB 的视图生成的。本地和测试没有办法重现是因为其实用的是 Mysql。


可恶,又是个线上问题!_spring_08

排查

这个环境问题还挺恶心的,因为没有 TIDB 的环境,只能自己装一个了去想办法重现一下了(过程很费时间)。

好在 Mac 装这些东西还是很方便的,安装、刷新环境变量、启动。

1. curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
2. source ${your_shell_profile}
3. tiup playground

然后本地按照那个很沙雕的创建视图的方法创建个视图出来,再本地 DEBUG 看看。

进来一看,和开始想的不一样,居然是个 null 字符串,不是我想象中的 ​​null​​,那这个看起来不应该会报空指针才对啊?!


可恶,又是个线上问题!_java_09

有点想不通为啥这里会空,然后打开这个类看了一眼。

嗯???

这尼玛??

?????

难道是拆箱导致的?


可恶,又是个线上问题!_sql_10

好吧,没错。​​dataTypeMap.get(dataType)​​ 是 null,拆箱调用的啥我不用说了吧,就是这原因。。。

修复

你说咋改?

有同学说了,那还不简单,你是个沙雕吗?改成​​Integer​​不就完事儿了。

嗯,你说的没错,我就这么改了。

然后,改完之后启动又是一堆报错,到处存在调用。

这玩意儿不能动,他仿佛在和我说,你动动试试,果然动动就逝世。


可恶,又是个线上问题!_数据库_11

文章写到这里,我还没想好怎么改,大概有 3 个方案:

  1. 完全去掉 TIDB 还用视图这离谱的操作,从根源上解决问题
  2. 按照这个方法,改成 Integer,就是不知道要改多少地方
  3. 不去加载视图的元数据,就可以避免这个问题了,毕竟这年头谁用视图啊

给大家个机会,去给他们提个 PR。