mysql 诡异的1054错误

发布时间:2017-6-29 10:23:14编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"mysql 诡异的1054错误",主要涉及到mysql 诡异的1054错误方面的内容,对于mysql 诡异的1054错误感兴趣的同学可以参考一下。

前言

今天在工作中遇到一个非常坑爹的问题,有关Mysql的异常处理,花费了我好几个小时的时间,最后终于解决了,然后根据出现的问题的原因,逆向来看自己解决问题的过程,发现网上的一些文章简直是太坑了,坑的人找不着北啊,最后总结一下吧,免得又踩到这个坑。

先交代一下环境和背景:问题出现在工作的项目中,工程代码在运行的过程中会调用事先定义好的存储过程来保存数据,因为字段太多,大概有好几百个,我就想着把一些废弃的字段删掉,这样一来可以加快存储速度,二来减小数据库的存储大小,于是说干就干,为了避免不必要的麻烦,我决定先改存储过程,在参数中去想不需要存储的字段, 等检测没有问题了再删除表中的字段,就当我改完的时候问题出现了,数据存不上了…

分析过程

是的,数据存不上了,但是程序不报错,理论上如果调用存储过程失败了,程序会打印出错误代码,比如:1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xxx' at line 1,但是并没有,我是通过存储过程中的异常打印发现错误的,就是这一句DECLARE EXIT HANDLER FOR SQLEXCEPTION CALL LogError("SetBaseData:SQLEXCEPTION");,存储过程中如果有这一句,当发生异常的时候就可以调用自定义函数LogError("SetBaseData:SQLEXCEPTION")来将错误信息打印到数据库中,可是程序代码为什么不报错呢?这我就想不明白了。

还是想来先来看一下存储过程的示例:

CREATE PROCEDURE SetBaseData(
  IN paramId INT,
  IN paramA INT,
  IN paramB INT,
  IN paramC INT,
  IN paramD INT,
  IN paramE INT,
  IN paramF INT,
  IN paramG INT
)
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION CALL LogError("SetBaseData: SQLEXCEPTION");
  UPDATE dataT SET
    A=paramA,
    B=paramB,
    C=paramC,
    D=paramD,
    E=paramE,
    F=paramF,
    G=paramG,
  WHERE Id=paramId; 
END; 

看了这个存储过程是不是感觉很简单,结构是很简单,但是实际的存储过程中可是有好几百个字段需要修改,所以很难查到问题,结果问题就出在我精简字段的过程中,比如我删除无用的字段改成了下面这个样子:

CREATE PROCEDURE SetBaseData(
  IN paramId INT,
  IN paramA INT,
  IN paramB INT,
  IN paramE INT,
  IN paramG INT
)
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION CALL LogError("SetBaseData: SQLEXCEPTION");
  UPDATE dataT SET
    A=paramA,
    B=paramB,
    E=paramE,
    F=paramF,
    G=paramG,
  WHERE Id=paramId; 
END; 

怎么样,发现问题了吗?这样小一个存储过程应该一眼就能发现问题,paramF参数已经删掉了,但是在Update语句中还在使用,这就能解释为什么会触发异常导致数据无法存储了,但是想在几百个字段中找出这样的问题真的很困难,并且参数的顺序和设置的顺序是不一样的,一开始我也没发现,只能在异常结果上分析,有人可能会问我为什么不在程序中下断点,虽然没有打印信息,但是看返回值总能发现问题吧,很遗憾,底层代码被封装了,我只能看到返回了错误的结果,但是却分辨不出是什么错误,奇就奇怪在这,原来存储过程返回错误都是有打印信息的啊。

既然代码看不到,我就只能从存储过程中找原因了,于是我想到使用更细化的异常处理,但是找了半天也不能直接输出异常类型,只能单个捕获,于是上网查了错误代码的分类,发现网上千篇一律的都是下图中的错误代码总结,这正是坑人的地方,其实就是抄来的。

Mysql error

于是我对着这些错误代码挨个检测把存储过程改成了这样:

CREATE PROCEDURE SetBaseData(
  IN paramId INT,
  IN paramA INT,
  IN paramB INT,
  IN paramE INT,
  IN paramG INT
)
BEGIN
  DECLARE EXIT HANDLER FOR 1021 CALL LogError("1021 ");
  DECLARE EXIT HANDLER FOR 1022 CALL LogError("1022 ");
  DECLARE EXIT HANDLER FOR 1027 CALL LogError("1027 ");
  DECLARE EXIT HANDLER FOR 1036 CALL LogError("1036 ");
  DECLARE EXIT HANDLER FOR 1048 CALL LogError("1048 ");
  DECLARE EXIT HANDLER FOR 1062 CALL LogError("1062 ");
  DECLARE EXIT HANDLER FOR 1099 CALL LogError("1099 ");
  DECLARE EXIT HANDLER FOR 1100 CALL LogError("1100 ");
  DECLARE EXIT HANDLER FOR 1104 CALL LogError("1104 ");
  DECLARE EXIT HANDLER FOR 1106 CALL LogError("1106 ");
  DECLARE EXIT HANDLER FOR 1114 CALL LogError("1114 ");
  DECLARE EXIT HANDLER FOR 1150 CALL LogError("1150 ");
  DECLARE EXIT HANDLER FOR 1165 CALL LogError("1165 ");
  DECLARE EXIT HANDLER FOR 1242 CALL LogError("1242 ");
  DECLARE EXIT HANDLER FOR 1263 CALL LogError("1263 ");
  DECLARE EXIT HANDLER FOR 1264 CALL LogError("1264 ");
  DECLARE EXIT HANDLER FOR 1265 CALL LogError("1265 ");
  DECLARE EXIT HANDLER FOR 1312 CALL LogError("1312 ");
  DECLARE EXIT HANDLER FOR 1317 CALL LogError("1317 ");
  DECLARE EXIT HANDLER FOR 1319 CALL LogError("1319 ");
  DECLARE EXIT HANDLER FOR 1325 CALL LogError("1325 ");
  DECLARE EXIT HANDLER FOR 1326 CALL LogError("1326 ");
  DECLARE EXIT HANDLER FOR 1328 CALL LogError("1328 ");
  DECLARE EXIT HANDLER FOR 1329 CALL LogError("1329 ");
  DECLARE EXIT HANDLER FOR 1336 CALL LogError("1336 ");
  DECLARE EXIT HANDLER FOR 1337 CALL LogError("1337 ");
  DECLARE EXIT HANDLER FOR 1338 CALL LogError("1338 ");
  DECLARE EXIT HANDLER FOR 1339 CALL LogError("1339 ");
  DECLARE EXIT HANDLER FOR 1348 CALL LogError("1348 ");
  DECLARE EXIT HANDLER FOR 1357 CALL LogError("1357 ");
  DECLARE EXIT HANDLER FOR 1358 CALL LogError("1358 ");
  DECLARE EXIT HANDLER FOR 1362 CALL LogError("1362 ");
  DECLARE EXIT HANDLER FOR 1363 CALL LogError("1363 ");
  DECLARE EXIT HANDLER FOR SQLEXCEPTION CALL LogError("SetBaseData: SQLEXCEPTION");
  UPDATE dataT SET
    A=paramA,
    B=paramB,
    E=paramE,
    F=paramF,
    G=paramG,
  WHERE Id=paramId; 
END; 

看到这里是不是觉得我丧心病狂,确实是,但是我没有办法了啊,可是事与愿违,这么狠毒的代码最终也没有捕获到错误,可见网上的常见错误代码其实没什么卵用,接下来我就想既然代码中不打印错误,那么我直接在Mysql客户端调用存储过程总行了吧,一开始没这么做主要是字段太多了,好几百个呀,现在没办法了,只能试一试我对照着参数的类型,一个个输入,最后call运行存储过程,诡异的事情发生了,没有任何报错,甚至警告都没有,但是数据还是没有保存上,简直要疯了。没办法最终只能一行一行的看存储过程的定义了,那可是好几百行啊,这种定义和C++代码不同,根本就没有跳转,只能靠脑袋记忆,我又没用IDE,只能硬着头皮看了,还好功夫不负有心人,最后让我发现了问题,就是paramF参数已经删掉了,但是在Update语句中还在使用这样的情况,于是我改正了过来,发现保存数据没有问题了。

可是我那么多捕获异常的代码就白写了吗?于是我又还原了回去,结果令人震惊的一幕发生了,程序就然报错了,就是我刚才改过的那一句,1054 - Unknown column 'paramF' in 'field list',你说奇不奇怪,我都找到问题了,你居然又明确的指出来了,早干嘛去了,不过这条消息还算有点用,起码让我知道这是”1054异常”啊,于是我把这个异常在存储过程中做了处理,加了一句DECLARE EXIT HANDLER FOR 1054 CALL LogError("1054 ");这次果然在调试信息中发现了这个错误,于是上网查了一下1054的含义,就是说某个变量没有出现在参数列表中.

为此我还查了一下Mysql的官网,发现Mysql的官网上列举了错误1002到4531总共有3000多个,看来网上的Mysql常见错误代码并不常见。

总结

  1. 通过这件事让我再一次发现代码的诡异
  2. 遇到问题还得相信自己,还是自己最靠谱
  3. 网上查资料要注意甄别,我发现网上流传的常见错误代码中连“1064 sql 语法错误”都没有包含,看来它并不常见
  4. 还是想直接在存储过程中输出异常的类型,不想一个个的捕获,我还没找到方法,希望有经验的大神能给我一点点指导。

附注

我还是把Mysql官网指出的错误贴在这:Mysql Error Codes


上一篇:[置顶] 异地恋的奇思妙想
下一篇:开发人员学Linux(7):CentOS7编译安装PHP并配置PHP

相关文章

相关评论

本站评论功能暂时取消,后续此功能例行通知。

一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!

二、互相尊重,对自己的言论和行为负责。

好贷网好贷款