日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

【转】MySQL sql_mode 说明(及处理一起 sql_mode 引发的问题)

發布時間:2025/3/16 数据库 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】MySQL sql_mode 说明(及处理一起 sql_mode 引发的问题) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. MySQL 莫名變成了 Strict SQL Mode

最近測試組那邊反應數據庫部分寫入失敗,app層提示是插入成功,但表里面里面沒有產生數據,而兩個寫入操作的另外一個表有數據。因為 insert 失敗在數據庫層面是看不出來的,于是找php的同事看下錯誤信息:

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

很明顯2個 insert 操作,第一條成功,第二條失敗了,但因為沒有控制在一個事務當中,導致app里面依然提示成功,這是客戶入庫操作,心想如果線上也有這個問題得是多大的代價。

不說開發的問題,好端端的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 | +---------------+--------------------------------------------+

但是一直是沒問題的的,就突然出現了,有誰會去改 sql_mode 呢,生產環境產生這個問題的風險有多大?所以必須揪出來。

先?set global sql_mode=''?,讓他們用著先(文后會給解決問題根本的辦法),同時打開general_log看是哪一個用戶有類似設置 sql_mode 命令:

1134456 Query SET autocommit=1 1134456 Query Set sql_mode='NO_ENGINE_SUBSITUTION,STRICT_TRANS_TABLES' 1134457 Connect ecuser@10.0.200.173 on 1134457 Query /* mysql-connector-java-5.1.35 ...

看出是java組那邊哪個框架建立連接的時候使用設置了sql_mode,但這是session級別的,不影響php那邊用戶的連接。

<!-- more -->

那會是什么原因在 set global 之后又變回strict模式呢,于是想到 mysqld_safe 啟動實際是一個保護進程,在mysqld異常停止之后會拉起來,會不會中間有異常導致 mysqld 重啟,致使 global 失效?看了mysql錯誤日志,才想到前些天斷過電,所以決定直接改?/etc/my.cnf配置:

[mysqld] sql_mode=NO_ENGINE_SUBSTITUTION

重啟myqld之后,還是STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,很少遇到my.cnf里面配置不生效的情況。無獨有偶,在 stackoverflow上找到同樣的問題?how-to-make-sql-mode-no-engine-substitution-permanent-in-mysql-my-cnf?,原因很簡單,sql_mode這個選項被其它地方的配置覆蓋了。

了解一下mysql配置文件的加載順序:

$ mysqld --help --verbose|grep -A1 -B1 cnf Default options are read from the following files in the given order: /etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf

mysql按照上面的順序加載配置文件,后面的配置項會覆蓋前面的。最后終于在?/usr/my.cnf?找到有一條sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,把這個文件刪掉,/etc/my.cnf 里面的就生效了。

但是目前沒能整明白的是,mysql運行這么長時間怎么突然在/usr?(MYSQL_BASE)下多個my.cnf,也不像人為創建的。其它實例也沒這樣的問題。

類似還出現過一例:存儲過程里把 '' 傳給int型的,嚴格模式是不允許,而非嚴格模式只是一個warning。(命令行執行完語句后,show warnings?可看見)

那么解決這類問題的終極(推薦)辦法其實是,考慮到數據的兼容性和準確性,MySQL就應該運行在嚴格模式下!無論開發環境還是生產環境,否則代碼移植到線上可能產生隱藏的問題。

sql_mode 問題可以很簡單,也可以很復雜。曾經在一個交流群里看到有人提到,主從sql_mode設置不一致導致復制異常,這里自己正好全面了解一下幾個常用的值,方便以后排除問題多個方向。

2. sql_mode 常用值說明

官方手冊專門有一節介紹?https://dev.mysql.com/doc/refman/5.6/en/sql-mode.html?。 SQL Mode 定義了兩個方面:MySQL應支持的SQL語法,以及應該在數據上執行何種確認檢查。

1. SQL語法支持類

  • ONLY_FULL_GROUP_BY?對于GROUP BY聚合操作,如果在SELECT中的列、HAVING或者ORDER BY子句的列,沒有在GROUP BY中出現,那么這個SQL是不合法的。是可以理解的,因為不在 group by 的列查出來展示會有矛盾。
    在5.7中默認啟用,所以在實施5.6升級到5.7的過程需要注意:

    Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column '1066export.ebay_order_items.TransactionID' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
  • ANSI_QUOTES?啟用 ANSI_QUOTES 后,不能用雙引號來引用字符串,因為它被解釋為識別符,作用與 ` 一樣。設置它以后,update t set f1="" ...,會報 Unknown column '' in 'field list 這樣的語法錯誤。

  • PIPES_AS_CONCAT?將?||?視為字符串的連接操作符而非 或 運算符,這和Oracle數據庫是一樣的,也和字符串的拼接函數 CONCAT() 相類似。

  • NO_TABLE_OPTIONS?使用?SHOW CREATE TABLE?時不會輸出MySQL特有的語法部分,如?ENGINE?,這個在使用 mysqldump 跨DB種類遷移的時候需要考慮。

  • NO_AUTO_CREATE_USER?字面意思不自動創建用戶。在給MySQL用戶授權時,我們習慣使用?GRANT ... ON ... TO dbuser?順道一起創建用戶。設置該選項后就與oracle操作類似,授權之前必須先建立用戶。5.7.7開始也默認了。

2. 數據檢查類

  • NO_ZERO_DATE?認為日期 '0000-00-00' 非法,與是否設置后面的嚴格模式有關。

  • 如果設置了嚴格模式,則 NO_ZERO_DATE 自然滿足。但如果是 INSERT IGNORE 或 UPDATE IGNORE,'0000-00-00'依然允許且只顯示warning

  • 如果在非嚴格模式下,設置了NO_ZERO_DATE,效果與上面一樣,'0000-00-00'允許但顯示warning;如果沒有設置NO_ZERO_DATE,no warning,當做完全合法的值。

  • NO_ZERO_IN_DATE情況與上面類似,不同的是控制日期和天,是否可為 0 ,即?2010-01-00?是否合法。

  • NO_ENGINE_SUBSTITUTION?使用?ALTER TABLE或CREATE TABLE?指定 ENGINE 時, 需要的存儲引擎被禁用或未編譯,該如何處理。啟用NO_ENGINE_SUBSTITUTION時,那么直接拋出錯誤;不設置此值時,CREATE用默認的存儲引擎替代,ATLER不進行更改,并拋出一個 warning .

  • STRICT_TRANS_TABLES?設置它,表示啟用嚴格模式。?
    注意?STRICT_TRANS_TABLES?不是幾種策略的組合,單獨指?INSERT、UPDATE出現少值或無效值該如何處理:

  • 前面提到的把 '' 傳給int,嚴格模式下非法,若啟用非嚴格模式則變成0,產生一個warning

  • Out Of Range,變成插入最大邊界值

  • 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,選了幾個代表性的,詳細還是?看手冊。

sql_mode一般來說很少去關注它,沒有遇到實際問題之前不會去啟停上面的條目。我們常設置的 sql_mode 是?ANSI、STRICT_TRANS_TABLES、TRADITIONAL,ansi和traditional是上面的幾種組合。

  • ANSI:更改語法和行為,使其更符合標準SQL
    相當于REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE

  • TRADITIONAL:更像傳統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

  • ORACLE:相當于 PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, NO_KEY_OPTIONS, NO_TABLE_OPTIONS, NO_FIELD_OPTIONS, NO_AUTO_CREATE_USER

無論何種mode,產生error之后就意味著單條sql執行失敗,對于支持事務的表,則導致當前事務回滾;但如果沒有放在事務中執行,或者不支持事務的存儲引擎表,則可能導致數據不一致。MySQL認為,相比直接報錯終止,數據不一致問題更嚴重。于是?STRICT_TRANS_TABLES?對非事務表依然盡可能的讓寫入繼續,比如給個"最合理"的默認值或截斷。而對于?STRICT_ALL_TABLES,如果是單條更新,則不影響,但如果更新的是多條,第一條成功,后面失敗則會出現部分更新。

5.6.6 以后版本默認就是NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,5.5默認為 '' 。

3. 設置 sql_mode

查看

查看當前連接會話的sql模式:mysql> select @@session.sql_mode; 或者從環境變量里取 mysql> show variables like "sql_mode";查看全局sql_mode設置: mysql> select @@global.sql_mode;只設置global,需要重新連接進來才會生效

設置

形式如 mysql> set sql_mode=''; mysql> set global sql_mode='NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES'; 如果是自定義的模式組合,可以像下面這樣 Adding only one mode to sql_mode without removing existing ones: mysql> SET sql_mode=(SELECT CONCAT(@@sql_mode,',<mode_to_add>')); Removing only a specific mode from sql_mode without removing others: mysql> SET sql_mode=(SELECT REPLACE(@@sql_mode,'<mode_to_remove>',''));

配置文件里面設置?sql-mode=""。

參考

  • MySQL manual sql-mode

  • mysql的sql_mode合理設置

  • set-sql-mode-blank-after-upgrading-to-mysql-5-6

  • MySQL SQL_MODE詳解


原文鏈接地址:http://seanlook.com/2016/04/22/mysql-sql-mode-troubleshooting/

轉載于:https://www.cnblogs.com/piperck/p/9835695.html

總結

以上是生活随笔為你收集整理的【转】MySQL sql_mode 说明(及处理一起 sql_mode 引发的问题)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。