MySQL is always eight hours short, how to break?

Today I'm going to talk about a simple topic. This is what a friend asked me on WeChat. For beginners, I can understand the troubles caused by this kind of problem, various attempts, various searches, and what others say is righteous, but it is I can't solve my own problem. Today, I will simply talk to you about this problem from two aspects. If you have other solutions, you can leave a message and share it together.

We can analyze this issue from two aspects:

  1. The problem with MySQL itself.
  2. Problems with Java code.

1. MySQL itself problem

MySQL itself is a problem. This is actually a good verification. Isn't it time? Let's execute the following SQL to see if the time on MySQL is consistent with the time on my computer:

select now();
复制代码

It can be seen that the time of MySQL is actually 8 hours different from the time of my system. The time of MySQL itself is not correct, so the time of your insert/query in the future will definitely not be correct.

Please pay attention to this query, either use command line operation, or use database tools such as Sqlyog, Navicat or Sequel Pro to operate, do not use JDBC to query, the specific reason will be understood after reading the second section.

When this problem occurs, it is most likely that the time zone of MySQL is not correct. We can reset the time zone for it.

First, let's check the current time zone of MySQL through the following command:

show variables like '%time_zone%';
复制代码

As you can see, MySQL says its time zone is SYSTEM, so what is SYSTEM? The first one says that SYSTEM is UTC (Coordinated Universal Time, also known as Universal Standard Time or Coordinated Universal Time). And our Beijing time is 8 hours faster than UTC, or UTC+8.

So now we need to correct the MySQL time zone first, which can be achieved by modifying the configuration file ( /etc/mysql/mysql.conf.d/mysqld.cnf), as follows:

After the modification is complete, restart MySQL, and then check the time zone of MySQL:

As you can see, the MySQL time zone is normal at this time.

Then there will be no problem in executing select now();it :

Some friends may think that modifying the configuration file is too troublesome, so you can also modify the time zone through SQL:

set global time_zone = Asia/Shanghai
复制代码

Note that our time zone is Asia/Shanghai, so don't write about other cities freely.

First we have to make sure that MySQL is fine.

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. 小结

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

Guess you like

Origin juejin.im/post/7085324249644302373