1. 程式人生 > >【MySQL】sql_mode引起的一個問題和總結

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

描述 簡單 5.5 style 半同步 l數據庫 默認值 ble 技術分享

【背景】

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

[Err] 1364 - Field `xx_field` doesnt have a default value

【排查與分析】

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

那麽看看吧,果然如此。

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默認為 ‘‘ 。

  

【解決】  

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

【總結】

  凡事講究舉一反三,PDCA。

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

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

  單獨指 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‘

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

更改語法和行為,使其更符合標準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。

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