没有一种合适的方式来捕捉和诊断 MySQL 服务器端的错误,因此想知道什么地方出错了基本上是不可能的。
我们使用下面这样一个查询来证明这个结论:
1
| INSERTINTOmy_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 的服务器端,例如是存储过程呢?则不行!
再看看下面的代码:
1
2
3
4
5
6
| CREATEPROCEDUREsome_procedure ()
BEGIN
DECLARECONTINUEHANDLER FORSQLEXCEPTION SET@error_found = 1;
INSERTINTOmy_table (my_column) VALUES(300);
IF @error_found THEN-- Any what error exactly is this? What's the message? END IF;
END; |
如果我们希望为指定的错误执行相应的动作,我们需要:
1
2
3
4
5
| DECLARECONTINUEHANDLER FOR1146 SET@error_found = 1146;
DECLARECONTINUEHANDLER FOR1147 SET@error_found = 1147;
DECLARECONTINUEHANDLER FOR1148 SET@error_found = 1148;
DECLARECONTINUEHANDLER FOR1149 SET@error_found = 1149;
... |
但如果我们比知道将会发生什么错误,但仍希望记录这个错误,这样我们可能需要定义成百上千的 HANDLERs,尽管如此还是无法覆盖所有的错误情况。
5.5 版本不是引入了 SINGAL 和 RESIGNAL 了吗?
是的,的确是引入了,但对你毫无帮助,你可以重新 RESIGNAL 一个错误,但并不意味着错误实际发生时你能知晓。