MySQL时区造成时差问题


Posted in MySQL onApril 13, 2022

前言

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

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

  • MySQL 本身的问题。
  • Java 代码的问题。

1. MySQL 本身问题

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

select now();

MySQL时区造成时差问题

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

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

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

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

show variables like '%time_zone%';

MySQL时区造成时差问题

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

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

MySQL时区造成时差问题

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

MySQL时区造成时差问题

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

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

MySQL时区造成时差问题

有的小伙伴可能嫌修改配置文件太麻烦了,那么也可以通过 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 类型。

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

MySQL时区造成时差问题

并且这个数据库的时区是 Asia/Shanghai

接下来我们创建一个 Spring Boot 项目,引入 Web、JDBC API 依赖和 MySQL 驱动,如下:

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);
}

MySQL时区造成时差问题

大家看到,这个查询结果查到的时间是 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 相关文章推荐
MySQL优化之如何写出高质量sql语句
May 17 MySQL
详解GaussDB for MySQL性能优化
May 18 MySQL
Mysql 如何实现多张无关联表查询数据并分页
Jun 05 MySQL
Mysql数据库中datetime、bigint、timestamp来表示时间选择,谁来存储时间效率最高
Aug 23 MySQL
关于MySQL中的 like操作符详情
Nov 17 MySQL
Mysql存储过程、触发器、事件调度器使用入门指南
Jan 22 MySQL
利用JuiceFS使MySQL 备份验证性能提升 10 倍
Mar 17 MySQL
MySQL中rank() over、dense_rank() over、row_number() over用法介绍
Mar 23 MySQL
MySQL数据库查询进阶之多表查询详解
Apr 08 MySQL
进阶篇之linux环境下安装MySQL数据库
Apr 09 MySQL
MySQL脏读,幻读和不可重复读
May 11 MySQL
Mysql数据库group by原理详解
Jul 07 MySQL
Mysql调整优化之四种分区方式以及组合分区
Apr 13 #MySQL
聊聊mysql都有哪几种分区方式
Apr 13 #MySQL
MySQL分区以及建索引的方法总结
Apr 13 #MySQL
MySQL分区路径子分区再分区
Apr 13 #MySQL
MySQL创建管理子分区
Apr 13 #MySQL
MySQL创建管理KEY分区
Apr 13 #MySQL
MySQL创建管理HASH分区
Apr 13 #MySQL
You might like
隐性调用php程序的方法
2009/03/09 PHP
php实现的一个很好用HTML解析器类可用于采集数据
2013/09/23 PHP
PHPStrom中实用的功能和快捷键大全
2015/09/23 PHP
php中array_column函数简单实现方法
2016/07/11 PHP
基于Jquery 解决Ajax请求的页面 浏览器后退前进功能,页面刷新功能实效问题
2010/12/11 Javascript
加载远程图片时,经常因为缓存而得不到更新的解决方法(分享)
2013/06/26 Javascript
jQuery实现的图片分组切换焦点图插件
2015/01/06 Javascript
js判断移动端是否安装某款app的多种方法
2015/12/18 Javascript
jQuery中实现prop()函数控制多选框(全选,反选)
2016/08/19 Javascript
微信小程序 toast 详解及实例代码
2016/11/09 Javascript
Postman的下载及安装教程详解
2018/10/16 Javascript
详解nodejs 配置文件处理方案
2019/01/02 NodeJs
vue.js this.$router.push获取不到params参数问题
2020/03/03 Javascript
vue+elementUI 实现内容区域高度自适应的示例
2020/09/26 Javascript
[04:07]显微镜下的DOTA2第八期——英雄复活动作
2014/06/24 DOTA
在centos7中分布式部署pyspider
2017/05/03 Python
opencv实现静态手势识别 opencv实现剪刀石头布游戏
2019/01/22 Python
深入分析python 排序
2020/08/24 Python
Python实现树莓派摄像头持续录像并传送到主机的步骤
2020/11/30 Python
英国工具中心:UK Tool Centre
2017/07/10 全球购物
Bluebella法国官网:英国性感内衣品牌
2019/05/03 全球购物
PPP协议组成及简述协议协商的基本过程
2015/05/28 面试题
一些Solaris面试题
2015/12/22 面试题
Linux面试题LINUX系统类
2014/11/19 面试题
入党申请书自我鉴定
2013/10/12 职场文书
新年寄语大全
2014/04/12 职场文书
行政专员求职信范文
2014/05/03 职场文书
经营目标管理责任书
2014/07/25 职场文书
帮一个朋友写的求职信
2014/08/09 职场文书
机动车登记业务委托书
2014/10/08 职场文书
酒店服务员岗位职责
2015/02/09 职场文书
财务工作失误检讨书
2015/02/19 职场文书
暂住证明怎么写
2015/06/19 职场文书
2016年优秀少先队辅导员事迹材料
2016/02/26 职场文书
JS继承最简单的理解方式
2021/03/31 Javascript
Python 数据科学 Matplotlib图库详解
2021/07/07 Python