What background

Recently, I did a small program shopping mall project (click to view, please pay attention to exchange). During the test, I found that some time fields in mysql database are 8 hours later than the current Beijing time, and some are normal. There is no need to think that there must be a time zone problem, but the weird thing is that not all time has a problem… After a thorough investigation, it was found that the root of the problem is a small time zone problem involving more than just the database, there are really many pits here, just to summarize.

Project System configuration

1. Java Springboot framework is used at the back end, and mysql is connected as follows

jdbc:mysql://localhost:3306/test_db? useUnicode=true&characterEncoding=UTF- 8 -&serverTimezone=Asia/Shanghai
Copy the code

Mysql is directly deployed with docker, the startup command is as follows:

docker run --rm --name mysql-test -e MYSQL_ROOT_PASSWORD=123456 -d mysql:latest
Copy the code

The mysql time field type is datetime, and the default value is CURRENT_TIMESTAMP.

`add_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation time'
Copy the code

Problem analysis

Let’s start by looking at where time zones are involved.

1, mysql time zone

Mysql > select * from time zone;

mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | UTC    |
| time_zone        | SYSTEM |
+------------------+--------+
2 rows in set (0.29 sec)

mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2021- 05- 12 11:41:05 |
+---------------------+
1 row in set (0.01 sec)
Copy the code

Time_zone indicates that mysql uses the system time zone. System_time_zone indicates that system uses the UTC time zone. The system time is 8 hours late. Now it is confirmed that there is a problem with the mysql time zone, but it still does not explain why some data times are normal

2. JDBC connection Settings

Let’s look at the JDBC connection string again and see that there is a time zone parameter serverTimezone=Asia/Shanghai.

jdbc:mysql://localhost:3306/test_db? useUnicode=true&characterEncoding=UTF- 8 -&serverTimezone=Asia/Shanghai
Copy the code

3. Analysis conclusions

Now, we can explain why some times are normal and some are not:

  1. Because mysql itself has a time zone problem, so the default value of a field with CURRENT_TIMESTAMP is written through mysql
  2. Since the TIME zone parameter is set for the JDBC connection string, the time to write to the database through the Java program is normal

From this, we can see that the time zone issue relates to mysql itself and its system (in this case docker, the default time zone of the Docker image is UTC), as well as the JDBC code level. Here are three ways to solve the time zone problem

The solution

1. Set the time zone of the Docker system

We first need to make sure that the time zone of the system on which mysql is running (docker in this case) is correct. There are two ways to set the time zone of docker

Method 1: Map native/etc/localtime(This method is to ensure that the docker system time zone is correct) Docker run--rm --name mysql-test -e MYSQL_ROOT_PASSWORD=123456 -v /etc/localtime:/etc/localtime -d mysql:latestMethod 2: Set environment variables-e TZ=Asia/Shanghai
docker run --rm --name mysql-test -e MYSQL_ROOT_PASSWORD=123456 -e TZ=Asia/Shanghai -d mysql:latest
Copy the code

Change the startup command to check the time zone of mysql

mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | CST    |
| time_zone        | SYSTEM |
+------------------+--------+
2 rows in set (0.00 sec)
Copy the code

Ok, now it’s CST, look at the generation time and it looks like everything is fine, but is it really fine? Search for CST and you’ll see the problem. Central Standard Time (USA) UTC-05:00 / UTC-06:00 2 Central Standard Time (Australia) UTC+ 09:303 China Standard Time UTC+08:00 4 This can cause problems when JDBC attempts to obtain the Time zone. For example, CST may be resolved to UTC-5 or UTC-6. Therefore, it is necessary to set the Time zone parameter for JDBC connection.

2. Set the time zone of mysql

It is highly recommended that you set the mysql time zone to +8:00 (where we are in east 8). There are also two ways to change the mysql time zone. Use 1 as appropriate. A temporary change

set global time_zone = From the '+'; Mysql > change the global time zone to Beijing time, but restart mysql server this setting is still invalidset time_zone = From the '+'; Flush PRIVILEGES; # Effective immediatelyCopy the code

2. Permanently modify the configuration file [Linux :my.cnf, Windows :my.ini]. Add: default-time_zone = ‘+8:00’ to the [mysqld] area and restart the mysql service.

Mysql time zone changed to +08:00

mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | CST    |
| time_zone        | +08:00 |
+------------------+--------+
2 rows in set (0.11 sec)
Copy the code

3. Set the time zone parameters for the JDBC connection

As you can see from my experience, if JDBC reads the wrong time zone, it will result in writing to the database at the wrong time, regardless of whether mysql is in the right time zone or not, so just passing the first two steps is not a foolproof guarantee. Therefore, be sure to add the time zone parameter serverTimezone=Asia/Shanghai to the JDBC connection string

Finally, a summary of ways to avoid time zone problems:

  1. First, ensure that the system time zone is correct
  2. Add the time zone parameter serverTimezone=Asia/Shanghai to the JDBC connection
  3. You are advised to set the time_zone parameter to +8:00. Do not use an ambiguous CST (even the default _SYSTEM_ value). In addition, try to use datetime type instead of timestamp type. This recommendation is also related to the field type, so I will not elaborate on it here. If you have any questions, please feel free to contact me

Github: github.com/frank-say/b… Gitee:gitee.com/frank-say/b… Click the experience