返回 登录
0

MySQL排错指南——语法错误

阅读2463

语法错误

这个错误听起来十分简单,但仍可能很难发现。我建议你像处理其他问题一样,非常细心地查找可能出现的SQL语法错误。

类似如下错误,很容易被发现:

在这个示例中,很显然用户少转入了个“m”,错误消息也很清楚(输出结果根据页面设置进行宽度调整):

..\tu\p1-2.tif{420}

遗憾的是,不是所有的语法错误都这么显而易见。我曾经处理过一个问题,它的查询语句是这样的:

这是一个版本迁移导致的问题;该语句在5.0版本中运行正常,但是在5.1版本中出现错误。问题的原因在于,在5.1版本中,“accessible”是一个保留字。给该语句加上引号(反引号还是双引号取决于你的SQL格式),即可重新正常运行:

实际场景中的查询语句看起来可能十分繁琐,包括大段的JOIN和复杂的WHERE条件。所以,即使是简单的错误在其他大量语句的干扰下也很难被查找出来。我们当时第一步的任务就是简化复杂的查询,使它变成像刚才看到的那样只有一行SELECT的语句。这就是一个最简化测试的示例。当我们看到简化后只有一行的语句也有同样的bug时,我们就能很快意识到原有程序是因为保留字的问题而产生了错误。

  • 第一教训就是教你把检查查询的语法错误作为排错的第一步。

但是,当你不知道查询是什么样的时候该怎么办?比如,查询是由应用程序自动生成的,或是在存储库中由第三方库动态生成的。

考虑如下PHP代码:

从这段脚本中很难直接定位错误。幸运的是,我们可以通过调整代码,使用输出函数打印查询语句。在PHP语言中,可以使用echo运算符。因此,修改代码,如下所示:

当程序输出将要提交的语句的时候,问题暴露出来了:

如果你仍然没有发现错误,你可以在MySQL命令行客户端中尝试执行这个查询:

问题在于每一行都少了一个右单引号。返回PHP代码,需要把:

改为:

即可。

  • 因此,一个重要的调试技巧是,始终尝试查看MySQL服务器最终接收到的查询。不要仅调试应用程序代码,要获取查询语句!

遗憾的是,你不可能始终使用输出函数。比如,我之前提到的那个场景,SQL语句是在编译好的第三方库中生成的。你的应用程序可能只是使用了库提供的高级的抽象接口,比如CRUD(新建、读、更新、删除)接口。或者在生产环境下,你不希望用户看到在使用特定参数对特定查询进行测试时的查询。在这种情况下,可以检查MySQL的通用查询日志。这里用一个新示例来说明其是如何工作的。

这是一段有问题的PHP代码:

..\tu\3-4.tif{445}

这段代码更新了例1.1中定义的表。

例1.1 一般问题情形的示例表

现在启用通用查询日志。该日志包含MySQL服务器接收到的每条独立查询。很多产品不会在日常运行中使用该日志,因为它在高负载的情况下增长十分迅速,并且写入日志会消耗MySQL服务器的资源,这些资源很可能用于更重要的用途。从5.1版本开始,你可以临时打开通用查询日志,方便随时记录你需要的查询。可以通过下面命令打开日志:

也可以将日志记录在表中,这可以帮你方便地分类索引日志文件项,因为你可以像查询其他表一样访问查询日志表:

现在可以运行应用程序。经过迭代地执行问题代码后,查询通用日志记录表,以查找有问题的查询:

..\tu\4-4.tif{329}


注意上述代码中2.row中的查询语句:

错误再次显而易见:在语句的结尾有个多余的逗号。这个问题是由下面这部分PHP代码产生的:

如果字符串确实是以逗号结尾的,那么rtrim函数本应移除结尾的逗号。但是现在这行实际上是以空格结尾的,因此rtrim函数没有移除任何字符。

既然我们已经发现了应用程序中产生错误的原因,我们就可以关闭通用查询日志:

在这节,我们学到一些重要的东西:

  • 语法错误可能是导致一些现实问题的原因;
  • 你应该测试与MySQL服务器接收到的请求完全一致的查询;
  • 编程语言的输出函数和通用查询日志可以帮助你快速定位由应用程序发送到MySQL服务器的查询的问题。

本文摘自《MySQL排错指南》

图片描述

关于这本书

《MySQL排错指南》由Oracle公司的技术支持工程师编写,详细阐述了MySQL故障诊断及处理中的知识,教会读者如何深入浅出地定位、分析并解决各种MySQL数据库的故障。

《MySQL排错指南》共分为7章,其内容涵盖了解决MySQL问题的基本技巧、MySQL中的并发问题、服务配置的影响、MySQL硬件和运行环境相关的问题、复制备份中的故障排除、故障排除使用的技术和工具,以及一些MySQL故障排除的最佳实践。

此外,本书的附录中还包含了可以帮助读者解决MySQL疑难问题的一些有用资源。《MySQL排错指南》适合MySQL数据库开发及运维人员阅读。

评论