MySQL运维实战(4.4) SQL_MODE之STRICT_TRANS_TABLES和STRICT_ALL_TABLES

俊达1年前技术文章526

如果设置STRICT模式,则如果数据写入时,如果数据不符合字段定义(字符串超出长度、数值类型数据超出范围、违反not null约束等),SQL会报错。

如果不设置STRICT模式,会对异常数据进行截断处理,SQL会显示Warning,但不报错。


对于组合型SQL,对于非事物型存储引擎,如MyISAM存储引擎,一个SQL中部分数据合法,部分数据不合法,则可能会在表中写入部分数据。


STRICT_ALL_TABLES

对于非事务型存储引擎如MyISAM,可能会出现批量Insert中部分数据写入成功、部分数据写入失败的情况。事务型存储引擎如InnoDB不存在该问题。

mysql> create table t_innodb(a int) engine=innodb;
Query OK, 0 rows affected (0.02 sec)

mysql> create table t_myisam(a int) engine=myisam;
Query OK, 0 rows affected (0.01 sec)

mysql> set sql_mode='STRICT_ALL_TABLES';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> insert into t_innodb values(1),('abc'),(3);
ERROR 1366 (HY000): Incorrect integer value: 'abc' for column 'a' at row 2

mysql> select * from t_innodb;
Empty set (0.00 sec)

mysql> insert into t_myisam values(1),('abc'),(3);
ERROR 1366 (HY000): Incorrect integer value: 'abc' for column 'a' at row 2

mysql> select * from t_myisam;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)


STRICT_TRANS_TABLES

如果设置strict_trans_tables SQL_MODE,则只影响事物型存储引擎。不影响往非事务型引擎中写入非法数据。

mysql> set sql_mode='STRICT_TRANS_TABLES';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> insert into t_innodb values(10),('abc'),(30);
ERROR 1366 (HY000): Incorrect integer value: 'abc' for column 'a' at row 2

mysql> insert into t_myisam values(10),('abc'),(30);
Query OK, 3 rows affected, 1 warning (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 1

mysql> show warnings;
+---------+------+--------------------------------------------------------+
| Level   | Code | Message                                                |
+---------+------+--------------------------------------------------------+
| Warning | 1366 | Incorrect integer value: 'abc' for column 'a' at row 2 |
+---------+------+--------------------------------------------------------+
1 row in set (0.01 sec)

mysql> select * from t_myisam;
+------+
| a    |
+------+
|    1 |
|   10 |
|    0 |
|   30 |
+------+
4 rows in set (0.00 sec)


不设置STRICT模式

不设置STRICT模式,则可以写入非法数据。SQL会有warning,非法的数据,会根据字段类型做相应的处理。

mysql> set sql_mode='';
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t_innodb values(100), ('abc');
Query OK, 2 rows affected, 1 warning (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 1

mysql> show warnings;
+---------+------+--------------------------------------------------------+
| Level   | Code | Message                                                |
+---------+------+--------------------------------------------------------+
| Warning | 1366 | Incorrect integer value: 'abc' for column 'a' at row 2 |
+---------+------+--------------------------------------------------------+
1 row in set (0.01 sec)

mysql> insert into t_myisam values(100), ('abc');
Query OK, 2 rows affected, 1 warning (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 1

mysql> show warnings;
+---------+------+--------------------------------------------------------+
| Level   | Code | Message                                                |
+---------+------+--------------------------------------------------------+
| Warning | 1366 | Incorrect integer value: 'abc' for column 'a' at row 2 |
+---------+------+--------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from t_innodb;
+------+
| a    |
+------+
|  100 |
|    0 |
+------+
2 rows in set (0.00 sec)

mysql> select * from t_myisam;
+------+
| a    |
+------+
|    1 |
|   10 |
|    0 |
|   30 |
|  100 |
|    0 |
+------+
6 rows in set (0.00 sec)


字符串类型

字符串类型的处理方式是截断超出长度的字符

mysql> set sql_mode='STRICT_ALL_TABLES';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> create table t_str(a varchar(3));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t_str values('abcd');
ERROR 1406 (22001): Data too long for column 'a' at row 1

mysql> select * from t_str;
Empty set (0.00 sec)



mysql>  set sql_mode='';
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t_str values('abcd');
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+----------------------------------------+
| Level   | Code | Message                                |
+---------+------+----------------------------------------+
| Warning | 1265 | Data truncated for column 'a' at row 1 |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

mysql> select * from t_str;
+------+
| a    |
+------+
| abc  |
+------+
1 row in set (0.00 sec)

数值类型

对于unsigned类型,插入负数会转换成0。如果数字超过允许的最大值,则截断为最大值


mysql> set sql_mode='STRICT_ALL_TABLES';

mysql> create table t_unsigned(a tinyint unsigned);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t_unsigned values(-1);
ERROR 1264 (22003): Out of range value for column 'a' at row 1

mysql> insert into t_unsigned values(256);
ERROR 1264 (22003): Out of range value for column 'a' at row 1

mysql> select * from t_unsigned;
Empty set (0.00 sec)

mysql> set sql_mode='';

mysql> insert into t_unsigned values(-1);
Query OK, 1 row affected, 1 warning (0.01 sec)

mysql> show warnings;
+---------+------+--------------------------------------------+
| Level   | Code | Message                                    |
+---------+------+--------------------------------------------+
| Warning | 1264 | Out of range value for column 'a' at row 1 |
+---------+------+--------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from t_unsigned;
+------+
| a    |
+------+
|    0 |
+------+
1 row in set (0.00 sec)

mysql> insert into t_unsigned values(256);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+--------------------------------------------+
| Level   | Code | Message                                    |
+---------+------+--------------------------------------------+
| Warning | 1264 | Out of range value for column 'a' at row 1 |
+---------+------+--------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from t_unsigned;
+------+
| a    |
+------+
|    0 |
|  255 |
+------+
2 rows in set (0.00 sec)


总结


建议设置STRICT_TRANS_TABLES。生产环境修改SQL_MODE需要先进行兼容性测试。


相关文章

MySQL运维实战之ProxySQL(9.5)proxysql和MySQL Group Replication配合使用

如果后端MySQL使用了Group Replication,可通过配置mysql_group_replication_hostgroups表来实现高可用mysql_group_replication_...

MySQL运维实战(5.2) MySQL charset基本概念

mysql多字符集mysql支持多字符集。一个数据库中可以存储不同字符集的数据,一个表的不同字段可以使用不同的字符集。mysql> show character s...

MySQL运维实战之备份和恢复(8.5)xtrabackup恢复增量备份

恢复增量备份时,需要先对基础全量备份进行恢复,然后再依次按增量备份的时间进行恢复。这个例子中,相关备份文件的目录结构如下:/data/backup ├── full │ &nb...

MySQL运维实战(1.1)安装部署:使用RPM进行安装部署

MySQL运维实战(1.1)安装部署:使用RPM进行安装部署

我们在生产环境部署mysql时,一般很少使用rpm。用rpm或或者其他包管理器安装mysql,好处是安装简单,而且很多系统可能都自带了某个版本的mysql。但是使用RPM安装也存在一些缺点:1、rpm...

 MySQL运维实战(1.2)安装部署:使用二进制安装部署

MySQL运维实战(1.2)安装部署:使用二进制安装部署

一般在生产环境,我们会使用二进制安装的方式安装MySQL。使用二进制安装,在处理单机多实例、升级MySQL等场景下更加方便。如果有特殊的需求(比如要打一些patch),我们还可以自己编译二进制。1、下...

MySQL运维实战(3.2) 常见数据库连接失败问题排查

如果数据库连接失败,可以从如下几方面来排查:1、客户端到服务端的网络是否畅通,服务端端口是否能连通。使用ping、telnet等工具探测服务端的端口是否能访问。[root@box3 ~]#&...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。