由于从去年2月份开始,Mysql5.6就不再维护了,所以公司决定往后的新项目最低都要采用Mysql5.7及以上的版本。 过程中出现了点问题,在这里记录且分享一下。
下面这条建表语句,在Mysql5.6版本中顺利执行,在Mysql5.7版本报错。
CREATE TABLE IF NOT EXISTS `tablename` (
`uid` bigint(64) DEFAULT 0,
`actid` int(10) DEFAULT 0 COMMENT '编号',
`tjson` text DEFAULT '' COMMENT '数据',
UNIQUE KEY `idx_uid` (`uid`,`actid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
这条建表语句在执行过程中有两个问题,首先是text类型默认值的问题。
`BLOB` and `TEXT` columns cannot have `DEFAULT` values.
这是Mysql5.6文档中对BLOB和TEXT类型的一句描述。大意就是BLOB和TEXT类型不能设置默认值。
看到这里我就好奇了,明明之前在Mysql5.6版本的时候执行初始化数据库的脚本时也没有报错呀?
于是我又仔细看了看在Mysql5.6版本下创建的表结构,还真发现了端倪。
建表语句中,我们把tjson字段设成了TEXT类型并且赋予默认值'' ,但是对比表结构和我们的建表语句,在Mysql5.6版本下创建的表并没有给TEXT类型的tjson赋予默认值,这么一来就和文档的内容呼应上了。
早在Mysql5.6的文档里就已经交代,TEXT类型是不能赋予默认值的。所以即使在5.6版本中执行成功,实际上TEXT类型的字段也没有默认值。那么为什么在5.6版本没有报错的代码,在5.7中版本却报错了呢?
在一番查询后,我发现了Mysql5.7又一个不同与5.6的地方,那就是MySQL5.7将默认的 sql_mode 从“松散模式”修改为了“严格模式”。
sql_mode支持设置多个值,其中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.
如果无法将给定的值插入到事务表中,则中止该语句。对于非事务表,如果值出现在单行语句或多行语句的第一行中,则中止语句。
从 MySQL 5.7.5 开始,默认sql_mode包括
STRICT_TRANS_TABLES.
Mysql5.7 sql_mode相关文档:dev.mysql.com/doc/refman/…
所以,在Mysql5.7.5默认开启STRICT_TRANS_TABLES的情况下,我们执行文章最初的建表语句,由于不允许给TEXT类型赋默认值,不符合“严格模式”的规范,导致中断了我们的建表语句。
只要通过设置,在sql_mode中不添加STRICT_TRANS_TABLES,建表语句就可以顺利执行了。
ps:在查询资料过程中发现了许多人在Mysql5.7版本下将TIMESTAMP类型的默认值设为 0000-00-00 00:00:00 也无法执行sql语句建表语句的情况,这个也是“严格模式”导致的。
TIMESTAMP数据类型用于同时包含日期和时间部分的值 。TIMESTAMP具有'1970-01-01 00:00:01'UTC 到'2038-01-19 03:14:07'UTC 的范围。 -- Mysql5.7文档
详情可以参考 dev.mysql.com/doc/refman/…
最后,文中有什么疑问或者错误的地方欢迎大家友好探讨~