前言

今天来聊一个简单的话题,这是一个小伙伴在微信上问我的,对于初学者我非常能理解这类问题带来的困扰,各种尝试,各种搜索,别人说的头头是道,但是就是解决不了自己的问题,今天我简单从两个方面来和大家聊聊这个问题,如果小伙伴们有其他的解决思路,也可以留言一起分享。

这个问题我们可以从两方面来分析:

  • mysql 本身的问题。
  • java 代码的问题。

1. mysql 本身问题

mysql 本身问题,这个其实很好验证,不就是时间么,我们执行如下 sql 看看 mysql 上的时间跟我的电脑时间是否是一致的:

select now();

可以看到,mysql 的这个时间跟我系统的时间其实就差了 8 小时,mysql 本身的时间都不对,那你将来插入/查询的时间肯定也不对。

这个查询大家注意,要么使用命令行操作,要么使用 sqlyog、navicat 或者 sequel pro 之类的数据库工具来操作,切勿使用 jdbc 来查询,具体原因一会看完第二小节就明白了。

出现这个问题,多半是 mysql 的时区不太对,我们重新给其设置一下时区即可。

首先我们通过如下指令来查看一下 mysql 当前的时区:

show variables like '%time_zone%';

可以看到,mysql 说它的时区是 system,那 system 又是啥呢?第一条说了 system 是 utc(协调世界时,又称世界标准时间或世界协调时间)。而我们的北京时间比 utc 快了 8 小时,即 utc+8。

所以我们现在要把 mysql 的时区先给改对,可以通过修改配置文件来实现(/etc/mysql/mysql.conf.d/mysqld.cnf),如下:

修改完成后,重启 mysql,再来查看 mysql 的时区:

可以看到,此时的 mysql 时区就正常了。

那么此时再执行 select now(); 也就不会有问题了:

有的小伙伴可能嫌修改配置文件太麻烦了,那么也可以通过 sql 来修改时区:

set global time_zone = asia/shanghai

注意我们所在的时区是 asia/shanghai,小伙伴们不要自由发挥写其他城市。

首先我们要确认 mysql 没问题。

2. jdbc 连接问题

当确认了 mysql 没有问题后,如果你的 mysql 时间还是不对,那么就有可能是 jdbc 连接的问题了。

这里我用大家常见的 jdbctemplate 来举个例子,其他的数据库框架操作也都是一样的,我这里主要是演示时区问题,数据操作细节问题就不再展示了。

首先我们来准备一个表,如下:

create table `user` (
  `id` int not null auto_increment,
  `createtime` datetime default null,
  `updatetime` timestamp null default null,
  `username` varchar(255) default null,
  primary key (`id`)
) engine=innodb auto_increment=6 default charset=utf8mb4 collate=utf8mb4_0900_ai_ci;

很简单的几个字段,createtime 是 datetime 类型,updatetime 是 timestamp 类型。

然后向表中添加一条记录:

并且这个数据库的时区是 asia/shanghai

接下来我们创建一个 spring boot 项目,引入 web、jdbc api 依赖和 mysql 驱动,如下:

然后我们来配置一下 mysql 的连接信息,如下:

spring.datasource.username=root
spring.datasource.password=123
spring.datasource.url=jdbc:mysql:///test01?servertimezone=utc

小伙伴们看一下,在数据库连接地址中,我特意设置了时区为 utc,这个时区比我们目前的时区慢了 8 小时,我们来看看用这样一个错误的时区,操作的结果是什么样子的。

@autowired
jdbctemplate jdbctemplate;
@test
void contextloads() {
    list<user> list = jdbctemplate.query("select * from user", new beanpropertyrowmapper<>(user.class));
    system.out.println("list = " + list);
}

大家看到,这个查询结果查到的时间是 21 点,跟 13 点相比快了 8 小时。

为啥呢?

因为我们连接地址中加了 servertimezone=utc 参数,这个时候,系统会把从数据库查询到的数据当成是 utc 时区的,即把 13 点当成 utc 时区的,但是我自己当前设备又是 asia/shanghai 时区,utc 时区的 13 点转成 asia/shanghai 时区之后就是 21 点了。

相同道理,大家也可以自行尝试设置 servertimezone=asia/tokyo,时区设置为东京,东京比我们早一个小时,东京的 13 点就是我们的 12 点,那么最终查询结果就是 12 点。

从这个案例中我们可以看到,jdbc 连接参数中的时区优先级高于 mysql 服务器的时区参数,所以这个连接参数大家也要尤其注意。

3. 题外话

有的小伙伴遇到的时区问题则是另外一种,返回 json 的时候时间不对。

如果在项目中用了 jackson,并且使用 @jsonformat 注解来格式化日期,就有可能出现时区问题,如下:

@jsonformat(pattern = "yyyy-mm-dd hh:mm:ss",timezone = "asia/shanghai")

大家看到,这段代码如果没有设置 timezone 属性,那么默认的时区就是 utc,也会导致最终的时间差了 8 小时。

4. 小结

到此这篇关于mysql总是差八个小时该如何解决的文章就介绍到这了,更多相关mysql差八个小时内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!