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. 你支持我嗎?
譯者注:后面內容翻譯的很糟糕,完全不知道在說什么,如果費勁請看英文原文或者共同翻譯下。