本地开发环境用的是mysql 8.0.17,而服务器因为使用的是centOS 7,所以默认装的DB是MariaDB 5.5.因此让我发现在建表时候,两个版本之间的巨大差异。本次仅针对ERROR 1293 (HY000)和1064 (42000)这两个错误。
首先,需求是:有几个字段是需要记录时间的,但是为了防止为空,所以给了默认值,默认值是当前系统的时间。上代码:
drop table IF EXISTS test.`t_test`;
CREATE TABLE test.`t_test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`firstLoginTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`lastLoginTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
上述语句建表失败
上面的建表语句,在我本地的环境(mysql 8.0.17)是可以完美运行的,并且测试了插入空数据,默认值确实是当前时间。这里请注意,我对于createTime
,firstLoginTime
和lastLoginTime
这三个字段,都是设置的timestamp
,并且默认值都是CURRENT_TIMESTAMP
。然后使用该语句到服务器(centOS 7)上面的环境运行(MariaDB 5.5)运行,直接报错,建表失败。
错误信息:
ERROR 1293 (HY000) at line 6 in file: 'test.sql': Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause
单纯分析错误提示,大概意思是,你只能给一个TIMESTAMP
类型的列赋值CURRENT_TIMESTAMP
;
测试1:去掉三个default值
use test;
drop table IF EXISTS test.`t_test`;
CREATE TABLE test.`t_test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`createTime` timestamp NOT NULL,
`firstLoginTime` timestamp NOT NULL,
`lastLoginTime` timestamp NOT NULL ,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
可以成功建表。
测试插入数据:insert into test.t_test (id) values(1);
结果:
+----+---------------------+---------------------+---------------------+
| id | createTime | firstLoginTime | lastLoginTime |
+----+---------------------+---------------------+---------------------+
| 1 | 2020-04-20 13:53:33 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |
+----+---------------------+---------------------+---------------------+
1 row in set (0.00 sec)
可以知道,对于timestamp
类型的,加入你不传值,那么第一个这个类型的字段,会默认为当前系统时间。但是还有两个字段并未满足我的需求,因此还需测试。
2. 测试插入数据:insert into test.t_test (id,createTime,firstLoginTime,lastLoginTime) values(2,null,null,null);
结果:
+----+---------------------+---------------------+---------------------+
| id | createTime | firstLoginTime | lastLoginTime |
+----+---------------------+---------------------+---------------------+
| 1 | 2020-04-20 13:53:33 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |
| 2 | 2020-04-20 17:56:23 | 2020-04-20 17:56:23 | 2020-04-20 17:56:23 |
+----+---------------------+---------------------+---------------------+
1 row in set (0.00 sec)
这次完全满足需求,也就是说,我们只需要设置传进去的entity类的相应属性为null,就可以实现表里面的数据是当前时间。当然,前提肯定是你设置了timestamp还有not null。
此时已经满足了需求,但是探索精神我们在测试一下,给一个default
值为now()
测试2:两个default值,一个CURRENT_TIMESTAMP
,一个now()
use test;
drop table IF EXISTS test.`t_test`;
CREATE TABLE test.`t_test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`firstLoginTime` timestamp NOT NULL DEFAULT NOW(),
`lastLoginTime` timestamp NOT NULL ,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
失败:ERROR 1293 (HY000) at line 5 in file: 'test.sql': Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause
可见,5.5版本的mariaDB,对于timestamp
类型,确实仅支持一个default
值,但是讨巧,还是可以完成设置默认值为当前时间的.那就是设置为NOT NULL
,但是VALUES
里面传NULL
进去,这个时候timestamp
会自动取当前时间。
从上面的图表可以看出,在5.5的时候,仅有timestamp是支持默认值的。如果是datetime,是不支持的。而在5.6以及往后的版本,是支持的。
其实是对上面需求的衍生——使用date_format()格式化日期并设为默认值
接我自己的需求,一开始自己没对timestamp
去细研究,就直接转换思路,既然datetime
或者timestamp
不接受我设置默认值,那么我直接把当前时间转化为字符串然后赋值给varchar
。
CREATE TABLE `t_test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`runningTime` bigint(20) DEFAULT '0' COMMENT 'device running time',
`firstLoginTime` varchar(255) NOT NULL DEFAULT (`date_format`(now(), '%Y-%m-%d %T')) comment 'device first login server time',
`lastLoginTime` varchar(255) NOT NULL DEFAULT (`date_format`(now(), '%Y-%m-%d %T')) comment 'device last login server time',
`lastOfflineTime` varchar(255) NOT NULL DEFAULT (`date_format`(now(), '%Y-%m-%d %T')) comment 'device last offline from server time',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
首先提示,将日期转换为字符串存到DB里面,并不是一个很明智的做法
暂时的我并未理解上面的提示的问题,但是我在stack overflow上面问问题的话,有位大佬是这样告诫我的。
上面的建表语句依然是会报错的,但仅限于MariaDB 10.2.1版本一下
错误:ERROR 1064 (42000) at line 27 in file: 'initEmgrTable_rel.sql': You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(
date_format(now(), '%Y-%m-%d %T')),
lastLoginTimevarchar(255) NOT NULL D' at line 34
可以看出,错误是出在默认值那里。我做过测试,直接改成default '11111111'
,可以把字段的默认值设置为1111111
,而改为default ('11111111')
则依然会报这个错误。也就是说,并非date_format
这个函数出错了。
varchar支持默认值,但是仅支持simple的值,如果你是类似子查询的赋值,那么无论是多么简单的查询,都是不支持的。而这种情况一直到MariaDB 10.2.1往后,才被修改。
yum -y list maria*
配置MariaDB更高版本的操作,我推荐看看这位仁兄的博客,我感觉写的很明白,别人的写的不甚清楚。CentOS 7安装高版本MariaDB
唯一需要补充的就是,如果你不想安装这位博主hahahafree MariaDB 10.4
的话,可以修改这里
只需要把这里的10.4改成你想要装的版本就行了,后面的centos7-amd64
可以改也可以不改,建议不改。
可以看一下阿里的源:
可以看到阿里的源里面是直接5.5和10.0往上的,你想要修改的版本一定要在这些里面,才能正确装进去