【MySQL】sql_mode引發的一個問題和總結

【背景】

  以前項目中,項目組計劃將現場的MySQL5.5升級到5.7,以提高主從同步性能、使用半同步複製,以及解決一些現場問題等。安排測試組進行驗證,測試同事反饋實驗室環境中發現有入庫失敗,我查看了error_log日誌,發現有很多以下報錯。mysql

[Err] 1364 - Field `xx_field` doesn't have a default value

 

【排查與分析】

  業務版本先後都是同樣的,好端端的mysql怎麼忽然就部分表寫入失敗呢?根據上面的日誌很快猜到是 sql_mode 問題: NOT NULL 列沒有默認值但代碼裏也沒給值,在非嚴格模式下,int列默認爲0,string列默認爲''了,因此不成問題;但在嚴格模式下,是直接返回失敗的。sql

       那麼看看吧,果真如此。數據庫

mysql> show variables like "sql_mode";
+---------------+--------------------------------------------+
| Variable_name | Value                                      |
+---------------+--------------------------------------------+
| sql_mode      | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |
+---------------+--------------------------------------------+

  但測試同事反饋並無更改過該參數。查閱資料,發現:MySQL5.6.6 之後版本默認就是NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,5.5默認爲 '' 。session

  

【解決】  

  嚴格模式是合理的,更能保證系統的健壯性,因此解決方案並非set global variables去除STRICT_TRANS_TABLES,而是業務側修改完善,加上默認值。性能

 

【總結】

  凡事講究觸類旁通,PDCA。測試

  • 本次出現問題的STRICT_TRANS_TABLES模式。 

  嚴格模式,進行數據的嚴格校驗,錯誤數據不能插入,報error錯誤。 spa

  單獨指 INSERTUPDATE出現少值或無效值該如何處理: 日誌

  1. '' 傳給int,嚴格模式下非法,若啓用非嚴格模式則變成0,產生一個warning
  2. Out Of Range,變成插入最大邊界值
  3. 非null字段沒有默認值,插入記錄時該字段缺失時報錯。A value is missing when a new row to be inserted does not contain a value for a non-NULL column that has no explicit DEFAULT clause in its definition

 

  • sql_mode取值不少,官方有打包組合,ANSI、TRADITIONAL,固然,每項也能夠單獨設置。注:大小寫不敏感,均可以。

1. sql_mode='ANSI'code

ANSI模式:寬鬆模式,對插入數據進行校驗,若是不符合定義類型或長度,對數據類型調整或截斷保存,報warning警告。blog

更改語法和行爲,使其更符合標準SQL,至關於REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE。

2.sql_mode='TRADITIONAL'

TRADITIONAL 模式:嚴格模式,當向mysql數據庫插入數據時,進行數據的嚴格校驗,保證錯誤數據不能插入,報error錯誤。用於事物時,會進行事物的回滾。

更像傳統SQL數據庫系統,該模式的簡單描述是當在列中插入不正確的值時「給出錯誤而不是警告」。

至關於 STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION。 

  • 其餘經常使用

set session sql_mode = 'no_auto_create_user';

MySQL5.7及以前版本可設置,MySQL8以後爲默認設置,先create user才能grant。 

 

set session sql_mode = 'no_zero_in_date';

set session sql_mode = 'no_zero_date';

no_zero_date認爲日期 '0000-00-00' 非法,與是否設置後面的嚴格模式有關。

  1. 若是設置了嚴格模式,則 NO_ZERO_DATE 天然知足。但若是是 INSERT IGNORE 或 UPDATE IGNORE,'0000-00-00'依然容許且只顯示warning
  2. 若是在非嚴格模式下,設置了NO_ZERO_DATE,效果與上面同樣,'0000-00-00'容許但顯示warning;若是沒有設置NO_ZERO_DATE,no warning,當作徹底合法的值。
  3. NO_ZERO_IN_DATE狀況與上面相似,不一樣的是控制日期和天,是否可爲 0 ,即 2010-01-00 是否合法。

 

set session sql_mode = 'no_engine_substitution';

使用 ALTER TABLE或CREATE TABLE 指定 ENGINE 時, 須要的存儲引擎被禁用或未編譯,該如何處理。

啓用NO_ENGINE_SUBSTITUTION時,此時直接拋出錯誤;

不設置此值時,CREATE用默認的存儲引擎替代,ATLER不進行更改,並拋出一個 warning。

相關文章
相關標籤/搜索