MySQL 服务器端的错误处理太弱了!
没有一种合适的方式来捕捉和诊断 MySQL 服务器端的错误,因此想知道什么地方出错了基本上是不可能的。
我们使用下面这样一个查询来证明这个结论:
INSERT INTO my_table (my_column) VALUES (300);
这个查询可能发生什么错误?
- 违反 UNIQUE KEY 约束
- 违反 FOREIGN KEY 约束
- my_column 字段类型可能是 TINYINT UNSIGNED, 而严格的 sql_mode 导致数值越界
- 后者字段类型可能是某个枚举,如 ENUM (2,3,5,8)
还有可能是这样一些错误:
- my_table 可能是一个只读的 MyISAM 表
- 我们对 my_table 进行了锁表操作 LOCK TABLES my_table READ -- 违反了锁
- 或者可能是一个 InnoDB 表,而 INSERT 可能导致死锁
- 配置了 read_only=1 只读
- 或者用户没法访问该表的权限
- 或者表不存在
- 也有可能是字段不存在
而且我还确定还可能有更多的错误原因存在。
现在,如果我写了一个 Java 程序,可能用了 Hibernate,那么我将会通过 SQLException 得到一个描述比较清晰的异常信息,我可以得知错误码和错误信息。
但在 MySQL 的服务器端,例如是存储过程呢?则不行!
再看看下面的代码:CREATE PROCEDURE some_procedure () BEGIN DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @error_found = 1; INSERT INTO my_table (my_column) VALUES (300); IF @error_found THEN -- Any what error exactly is this? What's the message? END IF; END;
如果我们希望为指定的错误执行相应的动作,我们需要:
DECLARE CONTINUE HANDLER FOR 1146 SET @error_found = 1146; DECLARE CONTINUE HANDLER FOR 1147 SET @error_found = 1147; DECLARE CONTINUE HANDLER FOR 1148 SET @error_found = 1148; DECLARE CONTINUE HANDLER FOR 1149 SET @error_found = 1149; ...
但如果我们比知道将会发生什么错误,但仍希望记录这个错误,这样我们可能需要定义成百上千的 HANDLERs,尽管如此还是无法覆盖所有的错误情况。
5.5 版本不是引入了 SINGAL 和 RESIGNAL 了吗?
是的,的确是引入了,但对你毫无帮助,你可以重新 RESIGNAL 一个错误,但并不意味着错误实际发生时你能知晓。
那么,问题是什么呢?
我想在服务器端做很多事情,而不是通过外部脚本如 Python/Perl/Java/Ruby/Shell 等,例如 event scheduler: 我的意思是有什么意义呢?如果在服务器端很多事情你没法做的话,那将是无用的。你不能够组织错误,不能得到足够的错误描述信息,这只不过是你想执行好工作的一小部分而已。
在 common_schema/QueryScript 中我提供了一些脚本,但错误处理该怎么办呢?我编写了一个完全不同的错误处理方法(尚未发布),但一旦在服务器端运行 common_schema , 因为服务器的限制导致其功能是有限的,也就是说用处的确很小。
本来不错
这是 error_count 连接会话变量,实际上也没有任何用途,有了下面两个变量就会好很多:
- last_error_code
- last_error_message
如果一个查询导致了多个错误,请选择其中一个。
或者使用其他方法来在服务器端解析 SHOW 命令(参考 这里). 如果我可以解析 SHOW ERRORS 命令,那么所有事情都能得以解决。
MySQL 5.0 引入了 INFORMATION_SCHEMA, 虽然并不完整。很快 SHOW 命令被排除在服务器端游标之外。因为太多的功能缺失,所以我提交了一个 bug report/feature request. 你支持我吗?
译者注:后面内容翻译的很糟糕,完全不知道在说什么,如果费劲请看英文原文或者共同翻译下。