首页 > 数据库 >解决 SpringBoot 应用中 MySQL 时区配置引起的时间不一致问题

解决 SpringBoot 应用中 MySQL 时区配置引起的时间不一致问题

时间:2024-07-20 17:11:15浏览次数:12  
标签:UTC SpringBoot 数据库 JVM 2024 插入 时间 一致 MySQL

在开发 SpringBoot 项目时,表中有两个时间字段

  • 一个通过 Java 代码使用 new Date() 方法获取当前时间再插入数据库
  • 另一个是使用 MySQL 的 CURRENT_TIMESTAMP 作为默认值

实际运行时发现数据库中的这两个时间值不一致,代码插入的时间比数据库自动生成的时间早了8小时,最终发现是 yml 配置问题

在此记录下我的解决过程,如有错误,欢迎指正!

1. 问题描述

开发环境:MySQL 5.7.19、Java 8、IntelliJ IDEA 2020.3

1.1 问题详情

  • Java 代码中设置用户加入时间
user.setJoinTime(new Date());
  • 数据库表的建表语句中 joinTimecreateTime 字段的定义
joinTime   datetime null
createTime datetime default CURRENT_TIMESTAMP
  • yaml 中的配置serverTimezone=UTC
spring:
    datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/thr?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
  • 运行代码后数据中插入数据后的时间值
    • joinTime:2024-07-14 08:49:19
    • createTime:2024-07-14 16:49:18

  • 现象:实际插入时间是 createTime,而 joinTime 按理来说应该与 createTime 的值一致,但从结果看出始终比实际时间早了八小时

1.2 原因分析

  • 时区对比

    • UTC (Coordinated Universal Time):协调世界时(UTC)是全球标准时间,作为时间的基准,不受地区时区影响

      • 时差:UTC+0,无时区偏移

      • 用途:广泛用于全球化的服务器和系统,以避免时区差异带来的复杂性

    • Asia/Shanghai (中国标准时间 CST):用于中国大陆地区

      • 时差:UTC+8,比UTC晚8小时

      • 用途:适用于中国本地化应用,时间存储和显示都基于北京时间,如果需要考虑1986年到1991年夏令时的历史数据,该时区会自动考虑这段时间夏令时的影响

  • 查看JVM默认时区:在Application文件中添加代码,运行程序,输出当前时间和时区信息

    • 运行结果JVM TimeZone: Asia/Shanghai
public static void main(String[] args) {
    System.out.println("JVM TimeZone: " + TimeZone.getDefault().getID());
    SpringApplication.run(Application.class, args);
}

  • 查看本地数据库时区:为东八区时间(北京时间)
SELECT @@global.time_zone, @@session.time_zone;

  • 分析:可以看出本地数据库和JVM时区其实都是东八区,而我在yml里配置的时区是 UTC,对照结果来看可知:
    • joinTime 字段使用 new Date() 在JVM默认时区(Asia/Shanghai)获取时间并插入,此时,JVM时间为北京时间 2024-07-14 16:49:19
    • 但由于数据库连接配置为UTC,实际插入时间会减去八小时,故转换为 2024-07-14 08:49:19(UTC时间)
    • createTime 字段本身就是数据库自动生成的,而我的数据库本地配置本来就是东八区时间,所以生成的时间没毛病

2. 解决

  • 将 yml 文件中的数据库连接配置修改为 serverTimezone=Asia/Shanghai 即可
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/thr?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai

3. 总结

  • serverTimezone=UTC 时,MySQL认为所有时间都是基于UTC时间,因此JVM的北京时间 2024-07-14 16:49:19 在插入时转换为 2024-07-14 08:49:19(UTC时间)
  • serverTimezone=Asia/Shanghai 时,MySQL认为所有时间都是基于北京时间,因此JVM的北京时间 2024-07-15 17:01:13 在插入时保持不变

4. 补充

  • 项目中后续又增加了 expireTime 字段,该字段是由前端传递过来然后插入数据库中的,发现了类似的问题
  • 前端原先传来的字段格式如下:
"expireTime": "2024-11-21T16:35:10.394Z"
  • 按理来说数据库中应该是:2024-11-21 16:35:10,可结果却增加了八小时,是 2024-11-22 00:35:10

  • 根据前面的经验分析:
    • "2024-11-21T16:35:10.394Z"Z 表示 UTC
    • 而我现在后端插入数据库的配置是 Asia/Shanghai,所以会将 16:35:10 增加八小时后再插入数据库
  • 解决办法:修改前端代码传过来的格式,传递符合 ISO 8601 格式的北京时间字符串
"expireTime": "2024-10-20T15:40:00+08:00"
  • 成功:

标签:UTC,SpringBoot,数据库,JVM,2024,插入,时间,一致,MySQL
From: https://www.cnblogs.com/thr-0103/p/18313395

相关文章

  • MySQL数据库 DQL操作
    一、数据库相关概念          1.数据库存储数据的仓库:数据是有组织的进行存储英文:DataBase,简称DB数据库就是将数据存储在硬盘上,可以达到持久化存储的效果2.数据库管理系统:管理数据库的大型软件......
  • springboot系列十: 自定义转换器,处理JSON,内容协商
    文章目录自定义转换器基本介绍应用实例查看源码注意事项和细节处理JSON需求说明应用实例内容协商基本介绍应用实例debug源码优先返回xml注意事项和细节⬅️上一篇:springboot系列九:接收参数相关注解......
  • 基于Flask + MySQL + PyQt5 +QtChart + HTML + js + CSS 的新冠数据大屏
    项目数据来源covid19_city_20211224.xlsx功能介绍数据清洗、存储数据增晒改查功能数据条件查询柱状图可视化饼状图可视化曲线图可视化雷达图可视化折线图可视化地图可视化使用到的库B端HTMLjsCSSechartsajaxC端PyQt5QtChartsqlalchemyFlaskMySQL项目启动安......
  • Springboot 启动时Bean的创建与注入(二)-面试热点-springboot源码解读-xunznux
    Springboot启动时Bean的创建与注入,以及对应的源码解读文章目录Springboot启动时Bean的创建与注入,以及对应的源码解读11、getBean:200,AbstractBeanFactory(org.springframework.beans.factory.support)12、doGetBean:335,AbstractBeanFactory(org.springframework......
  • 数据隔离级别查询一致导致重复退款
    @Transactional publicvoidupdateAfsState(){ Stringno="500001880002"; OrderReturnorderReturnDb=orderReturnModel.getOrderReturnByAfsSn(no); log.info("1.该售后单状态:{}",orderReturnDb.getState()); if(orderReturnDb.getState()......
  • 记一个引起MYSQL死锁Deadlock found when trying to get lock; try restarting transac
    一、记一个引起MYSQL死锁Deadlockfoundwhentryingtogetlock;tryrestartingtransaction的例子  今天在尝试MYSQL事务的时候,这种情况总会引起死锁,不知道为什么,我使用的测试MYSQL表的创建SQL如下:CREATETABLE`user`(`id`int(10)unsignedNOTNULLAUTO_INC......
  • SpringBoot+Vue的闲一品零食交易平台(前后端分离)
    技术栈JavaSpringBootMavenMySQLmybatisVueShiroElement-UI角色对应功能网站用户管理员项目功能截图......
  • SpringBoot+Vue的进存销管理系统(前后端分离)
    技术栈JavaSpringBootMavenMySQLmybatisVueShiroElement-UI角色对应功能管理员员工项目功能截图......
  • 基于Java Springboot餐厅点餐系统
    作者介绍:✌全网粉丝10W+本平台特邀作者、博客专家、CSDN新星计划导师、软件领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于项目实战✌一、作品包含源码+数据库+设计文档万字+全套环境和工具资源+部署教程二、项目技术前端技术:Html、Css......
  • 基于Java Springboot宠物管理系统
    作者介绍:✌全网粉丝10W+本平台特邀作者、博客专家、CSDN新星计划导师、软件领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于项目实战✌一、作品包含源码+数据库+设计文档万字+全套环境和工具资源+部署教程二、项目技术前端技术:Html、Css......