当前位置: 首页 > 后端技术 > Java

MySQL总是晚八小时,怎么破?

时间:2023-04-02 00:44:33 Java

今天来聊一个简单的话题。这是朋友在微信上问我的。对于初学者来说,这种题带来的困扰我能理解。各种尝试,各种搜索,别人说的头头是道,我就是解决不了自己的问题。今天我就从两个方面和大家简单谈谈这个问题。如果大家有其他的解决办法,也可以留言分享。我们可以从两个方面来分析这个问题:MySQL本身。Java代码的问题。1.MySQL自身的问题MySQL自身的问题,这个其实很容易验证,不就是时间吗,我们执行下面的SQL,看看MySQL上的时间和我电脑的时间是否一致:selectnow();可以看到,MySQL这个时间其实和我系统的时间相差了8个小时,而且MySQL本身的时间是错误的,所以你以后的插入/查询时间一定是错误的。这个查询请注意,要么使用命令行,要么使用Sqlyog、Navicat、SequelPro等数据库工具进行操作,不要使用JDBC查询,具体原因看完第二节就清楚了。出现这个问题,很有可能是因为MySQL的时区不对,我们可以为它重新设置时区。首先,让我们通过以下命令查看MySQL的当前时区:showvariableslike'%time_zone%';我们可以看到MySQL说它的时区是SYSTEM,那么SYSTEM是什么?第一篇说SYSTEM是UTC(CoordinatedUniversalTime,也叫UniversalStandardTime或UniversalCoordinatedTime)。而我们的北京时间比UTC早了8个小时,也就是UTC+8。所以我们需要先更改MySQL的时区,可以通过修改配置文件(/etc/mysql/mysql.conf.d/mysqld.cnf)来实现,如下:修改完成后,重启MySQL,然后查看MySQL时区:可以看到,此时MySQL时区是正常的。然后执行selectnow();这时候就没有问题了:有的朋友可能会觉得修改配置文件太麻烦,所以也可以通过SQL修改时区:setglobaltime_zone=Asia/Shanghai,注意我们所在的时间zone是Asia/Shanghai,朋友们别随便写别的城市了。首先我们需要确保MySQL是OK的。2、JDBC连接问题确认MySQL没有问题后,如果你的MySQL时间还是不对,那么可能是JDBC连接有问题。这里我以常用的JdbcTemplate为例。其他数据库框架操作同理。我这里主要演示时区问题,数据操作的细节就不展示了。首先,我们准备一个表如下:CREATETABLE`user`(`id`intNOTNULLAUTO_INCREMENT,`createTime`datetimeDEFAULTNULL,`updateTime`timestampNULLDEFAULTNULL,`username`varchar(255)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=6DEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_0900_ai_ci;很简单的字段,createTime是datetime类型,updateTime是Timestamp类型。然后在表中添加一条记录:并且这个数据库的时区是Asia/Shanghai接下来我们创建一个SpringBoot项目,引入Web、JDBCAPI依赖和MySQL驱动,如下:然后我们配置MySQL的连接信息,如下:spring.datasource.username=rootspring.datasource.password=123spring.datasource.url=jdbc:mysql:///test01?serverTimezone=UTC朋友们看看,在数据库连接地址里,我特意设置了时间时区为UTC,这个时区比我们现在的时区晚8小时。让我们看看在这样一个错误的时区下操作的结果是什么样的。@AutowiredJdbcTemplatejdbcTemplate;@TestvoidcontextLoads(){Listlist=jdbcTemplate.query("select*fromuser",newBeanPropertyRowMapper<>(User.class));System.out.println("list="+list);}可以看到,这个查询结果中找到的时间是21:00,比13:00快了8个小时。为什么?因为我们在连接地址中添加了serverTimezone=UTC参数,此时系统会认为从数据库中查询到的数据是UTC时区,即13点为UTC时区,但是我的当前设备处于Asia/Shanghai时区,UTC时区13:00转换为Asia/Shanghai时区后为21:00。同样的道理,你也可以尝试设置serverTimezone=Asia/Tokyo,时区设置为东京,东京比我们早一个小时,而东京的13:00就是我们的12:00,这样最后的查询结果现在是12:00。从本例中可以看出jdbc连接参数中的时区优先级高于MySQL服务器的时区优先级,所以要特别注意这个连接参数。3、跑题。一些朋友遇到的时区问题是另一种。返回JSON时时间错误。如果项目中使用了jackson,使用了@JsonFormat注解格式化日期,可能会出现时区问题,如下:@JsonFormat(pattern="yyyy-MM-ddHH:mm:ss",timezone="Asia/Shanghai")可以看到,如果这段代码没有设置timezone属性,那么默认的时区就是UTC,这也会导致最后的时间有8小时的时差。4.总结,这是宋哥总结的数据库的情况。如有补充欢迎留言讨论。