1. 問題
用戶表中有一個created_by
非空字段,表示是誰創建的這個用戶,因為系統默認有一個admin
用戶,故在創建表語句中有一條插入語句
insert into user(id,username,password) values('1','admin',MD5('admin'));
經過測試沒有問題,提交之后,同事找到我說sql腳本執行報錯,一看錯誤日志是created_by
字段沒有默認值
[Err] 1364 - Field `created_by` doesn't have a default value
相同的SQL語句在不同的環境中執行結果居然不一樣,經過調查,是兩個MySQL環境的sql_mode
不一樣導致的。
mysql> show variables like "sql_mode";
+---------------+--------------------------------------------+
| Variable_name | Value |
+---------------+--------------------------------------------+
| sql_mode | NO_ENGINE_SUBSTITUTION |
+---------------+--------------------------------------------+
sql_mode 問題: NOT NULL 列沒有默認值但代碼里也沒給值,在非嚴格模式下,int列默認為0
,string列默認為''
了,所以沒有問題;但在嚴格模式下,是直接返回失敗的。
2.查看與設置sql_mode
-- 查看當前連接會話的sql模式:
mysql> select @@session.sql_mode;
-- 或者從環境變量里取
mysql> show variables like "sql_mode";
-- 查看全局sql_mode設置:
mysql> select @@global.sql_mode;
-- 只設置global,需要重新連接進來才會生效
-- 將sql_mode設置為嚴格模式
mysql> SET sql_mode='STRICT_TRANS_TABLES';
3. sql_mode常用值
官方手冊專門有一節介紹SQL Mode,SQL Mode 定義了兩個方面:MySQL應支持的SQL語法,以及應該在數據上執行何種確認檢查。
SQL_MODE常用值
- ONLY_FULL_GROUP_BY:
對于GROUP BY聚合操作,如果在SELECT中的列,沒有在GROUP BY中出現,那么這個SQL是不合法的,因為列不在GROUP BY從句中
- NO_AUTO_VALUE_ON_ZERO:
該值影響自增長列的插入。默認設置下,插入0或NULL代表生成下一個自增長值。如果用戶 希望插入的值為0,而該列又是自增長的,那么這個選項就有用了。
- STRICT_TRANS_TABLES:
在該模式下,如果一個值不能插入到一個事務表中,則中斷當前的操作,對非事務表不做限制
- NO_ZERO_IN_DATE:
在嚴格模式下,不允許日期和月份為零
- NO_ZERO_DATE:
設置該值,mysql數據庫不允許插入零日期,插入零日期會拋出錯誤而不是警告。
- ERROR_FOR_DIVISION_BY_ZERO:
在INSERT或UPDATE過程中,如果數據被零除,則產生錯誤而非警告。如 果未給出該模式,那么數據被零除時MySQL返回NULL
- NO_AUTO_CREATE_USER:
禁止GRANT創建密碼為空的用戶
- NO_ENGINE_SUBSTITUTION:
如果需要的存儲引擎被禁用或未編譯,那么拋出錯誤。不設置此值時,用默認的存儲引擎替代,并拋出一個異常
PIPES_AS_CONCAT:
將"||"視為字符串的連接操作符而非或運算符,這和Oracle數據庫是一樣的,也和字符串的拼接函數Concat相類似
ANSI_QUOTES:
無論何種mode,產生error之后就意味著單條sql執行失敗,對于支持事務的表,則導致當前事務回滾;但如果沒有放在事務中執行,或者不支持事務的存儲引擎表,則可能導致數據不一致。MySQL認為,相比直接報錯終止,數據不一致問題更嚴重。于是 STRICT_TRANS_TABLES
對非事務表依然盡可能的讓寫入繼續,比如給個”最合理”的默認值或截斷。而對于 STRICT_ALL_TABLES
,如果是單條更新,則不影響,但如果更新的是多條,第一條成功,后面失敗則會出現部分更新。
5.6.6 以后版本默認就是NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
,5.5默認為 ‘’ 。
參考: