参考官方文档:

mysql可以为不同的客户端设置不同的sql_mode,并且每个应用能够设置他自己的会话级别的sql_mode。sql_mode会影响sql语法以及mysql显示数据的正确性。

When working with InnoDB tables, consider also the innodb_strict_mode system variable. It enables additional error checks for InnoDB tables.

官方文档建议:当使用innodb存储引擎表时,考虑使用innodb_strict_mode模式的sql_mode,它能增量额外的错误检测功能。

设置sql mode

mysql5.7默认的sql mode值如下:

root@(none) 05:48:26>show variables like "sql_mode";
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value                                                                                                                                     |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| sql_mode      | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.02 sec)

root@(none) 05:48:34>

在服务启动之前在配置文件中设置sql mode:

sql_mode="ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

或者在启动mysql的时候使用--sql-mode="value"来指定sql mode的值。

可以在命令行设置全局的sql mode,也可以设置会话级别的。

set global sql_mode="modes";        #全局的设置影响连接的每一个客户端,
set session sql_mode="modes";       #会话级别的设置只影响当前的客户端,

(需要说明的是,在命令行的设置重启服务后会失效)

mysql支持三种级别的sql mode

  • ANSI: 宽松模式,对插入数据进行校验,如果不符合定义类型或长度,对数据类型调整或截断保存,报warning警告。
  • STRICT_TRANS_TABLES:
    If a value could not be inserted as given into a transactional table, abort the statement. For a nontransactional table, abort the statement if the value occurs in a
    single-row statement or the first row of a multiple-row statement.
    #对于事务表,给的值不能插入则终止该语句。对于非事务表,若是单行语句或者多行语句的第一行则中断()

     

  • TRADITIONAL(traditional): mysql对插入的数据不会报警告而是直接给出错误。当使用的是事务表,发生错误时会直接回滚;若是非事务表则会造成数据的不一致的情况(错误前的数据已经插入)

mysql支持的所有模式

  • ALLOW_INVALID_DATES: 字母意思允许不合法的数据。不对日期做全面的检查,仅仅检查月份是否在1~12之间,天数是否在1~31之间;这种模式可能是有用的对web应用来说去获取年,月,日在三个不同的字段并且准确存储用户的输入数值,没有验证数据的合法性。这种模式对date和datetime类型有作用,但是对timestamp类型不起作用,timestamp总是要合法的数据。当ALLOW_INVALID_DATES启用时,服务端要求年和月时合法的。如果strict模式禁用,不合法的数据如"2004-04-31"被存储为"0000-00-00"并且审查警告;若严格模式启用则会生成错误。(最后这一句我确定没有翻译错,但是测试的时候,数据时原样插入的,没有转换为0000-00-00)
    root@testdb 06:19:08>create table tb2(l1 date);
    Query OK, 0 rows affected (0.22 sec)
    root@testdb 06:23:23>set session sql_mode="ALLOW_INVALID_DATES";
    Query OK, 0 rows affected, 1 warning (0.00 sec)
    
    root@testdb 06:23:41>insert into tb2 values("2012-02-30");
    Query OK, 1 row affected (0.00 sec)
    
    root@testdb 06:23:45>select * from tb2;
    +------------+
    | l1         |
    +------------+
    | 2012-02-30 |
    +------------+
    1 row in set (0.00 sec)
    
    root@testdb 06:23:56>insert into tb2 values("2012-04-31");
    Query OK, 1 row affected (0.09 sec)
    
    root@testdb 06:24:44>select * from tb2;
    +------------+
    | l1         |
    +------------+
    | 2012-02-30 |
    | 2012-04-31 |
    +------------+
    2 rows in set (0.00 sec)
    
    root@testdb 06:24:46>set session sql_mode="TRADITIONAL";
    Query OK, 0 rows affected, 1 warning (0.00 sec)
    
    root@testdb 06:26:26>insert into tb2 values("2012-06-31");
    ERROR 1292 (22007): Incorrect date value: '2012-06-31' for column 'l1' at row 1
    root@testdb 06:26:38>
    测试结果

相关文章: