MySQL的sql_mode合理設置

MySQL的sql_mode合理設置

​ sql_mode是個很容易被忽視的變量,默認值是空值,在這種設置下是能夠容許一些非法操做的,好比容許一些非法數據的插入。在生產環境必須將這個值設置爲嚴格模式,因此開發、測試環境的數據庫也必需要設置,這樣在開發測試階段就能夠發現問題.python

1.sql model 經常使用來解決下面幾類問題:

  (1) 經過設置sql mode, 能夠完成不一樣嚴格程度的數據校驗,有效地保障數據準備性。mysql

  (2) 經過設置sql model 爲寬鬆模式,來保證大多數sql符合標準的sql語法,這樣應用在不一樣數據庫之間進行遷移時,則不須要對業務sql 進行較大的修改。sql

  (3) 在不一樣數據庫之間進行數據遷移以前,經過設置SQL Mode 可使MySQL 上的數據更方便地遷移到目標數據庫中。數據庫

2.sql_mode經常使用值以下:

1. ONLY_FULL_GROUP_BY:

       對於GROUP BY聚合操做,若是在SELECT中的列,沒有在GROUP BY中出現,那麼這個SQL是不合法的,由於列不在GROUP BY從句中。

   2. NO_AUTO_VALUE_ON_ZERO:

      該值影響自增加列的插入。默認設置下,插入0或NULL表明生成下一個自增加值。若是用戶但願插入的值爲0,而該列又是自增加的,那麼這個選項就有用了。

   3. STRICT_TRANS_TABLES:嚴格模式

      在該模式下,若是一個值不能插入到一個事務表中,則中斷當前的操做,對非事務表不作限制。

   4. NO_ZERO_IN_DATE:

      在嚴格模式下,不容許日期和月份爲零。
 
   5. NO_ZERO_DATE:

      設置該值,mysql數據庫不容許插入零日期,插入零日期會拋出錯誤而不是警告。
  
   6. ERROR_FOR_DIVISION_BY_ZERO:

      在INSERT或UPDATE過程當中,若是數據被零除,則產生錯誤而非警告。若是未給出該模式,那麼數據被零除時MySQL返回NULL
 
   7. NO_AUTO_CREATE_USER:

      禁止GRANT建立密碼爲空的用戶

   8. NO_ENGINE_SUBSTITUTION:

      若是須要的存儲引擎被禁用或未編譯,那麼拋出錯誤。不設置此值時,用默認的存儲引擎替代,並拋出一個異常

   9. PIPES_AS_CONCAT:

      將"||"視爲字符串的鏈接操做符而非或運算符,這和Oracle數據庫是同樣的,也和字符串的拼接函數Concat相相似

   10. ANSI_QUOTES:

      啓用ANSI_QUOTES後,不能用雙引號來引用字符串,由於它被解釋爲識別符

    ORACLE的sql_mode設置等同:PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, NO_KEY_OPTIONS, NO_TABLE_OPTIONS, NO_FIELD_OPTIONS, NO_AUTO_CREATE_USER.

    若是使用mysql,爲了繼續保留你們使用oracle的習慣,能夠對mysql的sql_mode設置以下:

    在my.cnf添加以下配置

    [mysqld]
    sql_mode='ONLY_FULL_GROUP_BY,NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,
    ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,PIPES_AS_CONCAT,ANSI_QUOTES'

3.寬鬆模式 和 嚴格模式 的注意事項:

【1】注意:MySQL5.6和MySQL5.7默認的sql_mode模式參數是不同的。
    5.6的mode是NO_ENGINE_SUBSTITUTION,其實表示的是一個空值,至關於沒有什麼模式設置,能夠理解爲寬鬆模式。
    5.7的mode是STRICT_TRANS_TABLES,也就是嚴格模式。
    
【2】若是設置的是寬鬆模式,那麼咱們在插入數據的時候,即使是給了一個錯誤的數據,也可能會被接受,而且不報錯。
    
    例如:我在建立一個表時,該表中有一個字段爲name,給name設置的字段類型時char(10),若是我在插入數據的時候,其中name這個字段對應的有一條數據的長度超過了10,例如'1234567890abc',超過了設定的字段長度10,那麼不會報錯,而且取前十個字符存上,也就是說你這個數據被存爲了'1234567890',而'abc'就沒有了,可是咱們知道,咱們給的這條數據是錯誤的,由於超過了字段長度,可是並無報錯,而且mysql自行處理並接受了,這就是寬鬆模式的效果。
    
    其實在開發、測試、生產等環境中,咱們應該採用的是嚴格模式,出現這種錯誤,應該報錯纔對,因此MySQL5.7版本就將sql_mode默認值改成了嚴格模式,而且咱們即使是用的MySQL5.6,也應該自行將其改成嚴格模式。
    
    另外,MySQL等等的這些數據庫,都是想把關於數據的全部操做都本身包攬下來,包括數據的校驗,其實好多時候,咱們應該在本身開發的項目程序級別將這些校驗給作了,雖然寫項目的時候麻煩了一些步驟,可是這樣作以後,咱們在進行數據庫遷移或者在項目的遷移時,就會方便不少。mysql除了數據校驗以外,你慢慢的學習過程當中會發現,它可以作的事情還有不少不少,將你程序中作的好多事情都包攬了。
    
【3】改成嚴格模式後可能會存在的問題:

    若設置模式中包含了NO_ZERO_DATE,那麼MySQL數據庫不容許插入零日期,插入零日期會拋出錯誤而不是警告。
    例如:表中含字段TIMESTAMP列(若是未聲明爲NULL或顯示DEFAULT子句)將自動分配DEFAULT '0000-00-00 00:00:00'(零時間戳),也或者是本測試的表day列默認容許插入零日期 '0000-00-00' COMMENT '日期';這些顯然是不知足sql_mode中的NO_ZERO_DATE而報錯。

4.模式設置和修改(以解決上述問題爲例):

【方式一】:
    先執行select @@sql_mode,複製查詢出來的值並將其中的NO_ZERO_IN_DATE,NO_ZERO_DATE刪除,而後執行set sql_mode = '修改後的值'或者set session sql_mode='修改後的值';
    
    例如:set session sql_mode='STRICT_TRANS_TABLES';改成嚴格模式
    
    注意:此方法只在當前會話中生效,關閉當前會話就不生效了。


【方式二】:
    先執行select @@global.sql_mode,複製查詢出來的值並將其中的NO_ZERO_IN_DATE,NO_ZERO_DATE刪除,而後執行set global sql_mode = '修改後的值'。

    注意:此方法在當前服務中生效,從新MySQL服務後失效
 
【方法三】:
    1.在mysql的安裝目錄下,或my.cnf文件(windows系統是my.ini文件),新增 sql_mode = 
    "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

    添加my.ini以下:
    
    [mysqld]
    
    sql-mode="ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

    2.而後重啓mysql。以管理員身份運行CMD,執行 net stop mysql ,再執行 net start mysql。

    注意:此方法永久生效.固然生產環境上是禁止重啓MySQL服務的,因此採用‘方式二+方式三’來解決線上的問題,那麼即使是有一天真的重啓了MySQL服務,也會永久生效了。
相關文章
相關標籤/搜索