乐趣区

关于mysql:MySQL-总是差八个小时如何破

明天来聊一个简略的话题,这是一个小伙伴在微信上问我的,对于初学者我十分能了解这类问题带来的困扰,各种尝试,各种搜寻,他人说的有条有理,然而就是解决不了本人的问题,明天我简略从两个方面来和大家聊聊这个问题,如果小伙伴们有其余的解决思路,也能够留言一起分享。

这个问题咱们能够从两方面来剖析:

  1. MySQL 自身的问题。
  2. 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. 小结

好啦,这就是松哥总结的数据库的几种状况,小伙伴们如有补充欢送留言探讨。

退出移动版