问题描述
项目大联调时发现,原本访问A库的操作,最后操作到了B库中了,但是是偶尔操作到B库,这个时候回报错,偶尔操作成功。最后发现一个配置出错,就是A这个库在我们服务器中并不存在,但是我们的客户端应该在这种情况下是能够收到服务器的通知,表示db错误,但是实际上却没有。
复现问题
我们在本地测试机上复现下这个问题。复现过程如下:
首先我们验证了下故意写错dbname,会不会连接成功,事实证明连接成功。
然后访问接口,第一次访问出错,然后我在命令行下手动切换到正确的db下再访问接口,第二次正确。
然后我把mysql服务改为我们自己的测试的mysql。就会报错,报错信息如下:
说明正常来说db错误服务器是会提示我们错误的,但是这个项目的mysql很奇怪的没有。
问题查找过程
0x00
首先想到的问题可能是c++
版本太老导致的bug。后来我查看了下我们本地mysql和测试的mysql版本发现两个版本一直,都是5.6,加之搜索该问题也没搜到关注c++
客户端不兼容的问题反馈。
0x01
在从客户端版本找问题失败后,我尝试从JAVA和php客户端连接kfc的db来尝试,迂回的验证是不是c++版本问题,最后的结果是:
- Java客户端连接成功。
- PHP客户端连接成功,但是执行的时候会报db.table表不存在。说明php在执行语句的时候是带上了db名称的,比较严谨,所以真正执行sql语句的时候才会报错,但创建连接成功也是不应该。
从以上两方面佐证,其他语言的客户端也是能正确连接mysql服务器,在db不正确的情况下。也说明不是c++客户端的问题。
0x02
在证明不是客户端问题的情况下,我怀疑是测试的mysql服务有瑕疵,所以直接联系op来说明这个问题。
我首先让op帮忙看看服务器是否有错误日志,如果有错误日志,说明mysql能感知到这个错误,如果没有错误日志,那我就可以理所当然的赖mysql服务器的问题了。事实说明,mysql服务器没有感知到这个错误。
经过op的查证以及提醒,最后问题的答案揭晓了。
问题原因
联调环境下的mysql给所有用开放了权限,这个权限开放后,你进入mysql后,不需要执行use db就可以执行sql语句,不会报错”No database selected”
而正常的mysql服务是强制要求选择db后才能操作db。
那为什么不用选择db也能操作sql语句呢?
因为他有默认db,你最后一次操作退出时的db就是默认的db。这个从我们复现这个问题的视频里面就能看出来,这也是联调时时而成功时而失败的原因。
触发这个问题的条件如下:
- mysql赋值语句用的是
*.*
- mysql采用的不是直连,而是proxy。测试用的mysql是开源的proxy->kingshard,不是直连。
- 客户端配置db时出错,操作过程中更改db退出,才会出现时而处于正确的db,时而处于错误的db。
- mysql客户端连接mysql服务,执行sql语句时,没有严格带上db。php是严格带上的。
解决方法
- c++客户端执行sql语句加上dbname。
- mysql服务器需要精确授权。