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

俊达2年前技术文章856

如果设置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运维实战之备份和恢复(8.5)xtrabackup恢复增量备份

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

MySQL运维实战之备份和恢复(8.6)将数据库恢复到指定时间点

恢复到指定时间点使用全量备份和增量备份文件,都只能将数据库恢复到备份结束的时间。通过binlog,可以将数据库恢复到任意时间点(前提是备份和该时间点之间的binlog都存在)。找到时间点对应的binl...

MySQL运维实战(7.2) MySQL复制server_id相关问题

MySQL运维实战(7.2) MySQL复制server_id相关问题

主库server_id没有设置主库没有设置server_idGot fatal error 1236 from master when&nb...

MySQL运维实战之ProxySQL(9.4)proxysql和后端MySQL自动切换

MySQL运维实战之ProxySQL(9.4)proxysql和后端MySQL自动切换

如上图架构,当后端MySQL主库出现问题,发生主备切换后,如何自动将ProxySQL的读写切换到新的主库上?可以通过mysql_replication_hostgroups表配置实现:insert&n...

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

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

MySQL优化器特性(一)IN和Exists(semijoin)子查询优化策略

这篇文章中的SQL和执行计划在mysql 8.0.31环境下进行测试。测试的表结构和数据:表结构mysql> show create table tp\G...

发表评论    

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