MySql数据库时区问题

在Java Spring Boot应用中,发现插入数据库的时间比实际时间少几个小时。问题源于时区设置不一致,数据库时区与应用程序时区不同。解决办法是在JDBC连接字符串中指定`serverTimezone`,确保与应用时区一致,防止SimpleDateFormat在格式化时间时导致的时间差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:
往数据库插入数据时,发现时间比当前的时刻少了几个小时。
什么情况??

先来模拟一下事故现场
简单的设置一个时间,并插入数据库

@Service
public class Test {
    @Autowired
    TsMapper tsMapper;
    
    @PostConstruct
    public void init() throws ParseException {
        TimeEntity timeEntity = new TimeEntity();
        Date nowDate = new Date();
        timeEntity.setTs(nowDate);
         tsMapper.insert(timeEntity);
    }
}

debug来看,时间是正确的。
在这里插入图片描述

再查看一下数据库的时间:
在这里插入图片描述
数据库时间比应用成面看到的时间少

怎么回事? 百度一下,发现是时区的问题。
使用【show variables like ‘%time_zone%’;】语句查看了数据库的时区。

为什么时区对应不上,时间就会出现不一致了?
带着这样的疑问,debug一下代码,最终发现,在拼接sql中的时间参数时,会调用
com.mysql.cj包下ClientPreparedQueryBindings类中的bindTimestamp方法

    public void bindTimestamp(int parameterIndex, Timestamp x, Calendar targetCalendar, int fractionalLength, MysqlType targetMysqlType) {
      
        x = TimeUtil.adjustNanosPrecision(x, fractionalLength, !this.session.getServerSession().isServerTruncatesFracSecs());
        
        StringBuffer buf = new StringBuffer();

  		...
  		//使用带有分区的SimpleDateFormat对传进来的时间进行格式化
            this.tsdf = TimeUtil.getSimpleDateFormat(this.tsdf, "''yyyy-MM-dd HH:mm:ss",
                    targetMysqlType == MysqlType.TIMESTAMP && this.preserveInstants.getValue() ? this.session.getServerSession().getSessionTimeZone()
                            : this.session.getServerSession().getDefaultTimeZone());
            buf.append(this.tsdf.format(x));
       
		...

        setValue(parameterIndex, buf.toString(), targetMysqlType);
    }

其中tsdfSimpleDateTime
最终拼接成sql的时间,是通过simpleDateTime格式化Date得来的。
破案了,同样的时刻,由于SimpleDateFormat的时区不一致,导致格式化后的时间不一致,写入数据库的时间和应用程序时间出现不同。

SimpleDateTime的分区由什么决定?
这个分区当 JDBC 与 MySQL 开始建立连接时,如果没有设置JDBC连接串中的【serverTimezone】,则以数据库时区为准。

如何解决?
保证SimpleDateFormate的时区和应用程序时区一致

那如何控制SimpleDateFormat的时区?
非常简单,只需要再jdbc连接串中加上serverTimezone,指明时区为应用程序时区。例如:
jdbc:mysql://localhost:3306/sys?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8

总结

数据库时间和应用程序不一致的原因

  • 应用程序所在的时区和数据库不一致
  • mybatisPlus填充时间参数时,采用SimpleDataFormat对时间进行格式化,由于SimpleDataFormat采用的数据库时区,导致数据不一致

有两种处理方法:

  • 修改数据库时区,使其和应用程序时区保持一致
  • jdbc连接串的时候,指定时区为应用程序时区
<think>嗯,用户问的是如何查询MySQL数据库时区设置。我之前看过相关的文档,记得有两种方法。首先,可能需要用系统变量来查看时区,比如使用`@@global.time_zone`和`@@session.time_zone`。另外,还可以通过执行`SHOW VARIABLES`命令来查看时区相关的变量,比如`time_zone`和`system_time_zone`。 对了,用户可能是在使用Docker部署MySQL时遇到了时区问题,因为容器默认时区可能与宿主机不同。这时候可能需要修改配置文件或者启动参数来设置时区。不过用户现在只是询问如何查询,所以重点放在查询方法上。 需要检查命令的正确性。比如,`SELECT @@global.time_zone, @@session.time_zone;`这个语句是否正确,返回的结果可能显示SYSTEM或者具体的时区,比如+08:00。另外,`SHOW VARIABLES LIKE '%time_zone%';`应该会列出多个相关的变量,包括全局和会话级别的设置。 还要注意区分全局时区和会话时区,全局时区影响整个服务器,而会话时区只影响当前连接。用户可能需要知道两者的区别,所以在回答中需要解释清楚。 另外,是否需要提到时区时间相关函数的影响?比如NOW()和CURRENT_TIMESTAMP()会受时区设置影响,而UTC_TIMESTAMP()不会。这部分可能对用户有帮助,但用户的问题主要是查询设置,所以可能作为补充信息。 最后,确保引用正确的参考资料,用户提供的引用1和2中提到了查看时区的方法,需要正确标注引用标识。</think>### 如何查询 MySQL 数据库时区设置? #### 1. **查看全局和会话时区** 通过以下 SQL 语句可以直接查询全局时区(影响整个服务器)和会话时区(影响当前连接)的配置: ```sql SELECT @@global.time_zone AS '全局时区', @@session.time_zone AS '会话时区'; ``` - 若结果为 `SYSTEM`,表示时区与操作系统一致。 - 若显示具体时区(如 `+08:00`),则明确表示偏移量[^1]。 #### 2. **查看详细的时区变量** 使用 `SHOW VARIABLES` 命令查看与时间相关的所有配置: ```sql SHOW VARIABLES LIKE '%time_zone%'; ``` 输出示例: ``` Variable_name | Value -------------------|---------- system_time_zone | CST time_zone | SYSTEM ``` - `system_time_zone` 表示操作系统的时区(如 `CST` 表示中国标准时间)。 - `time_zone` 表示 MySQL 当前使用的时区模式(`SYSTEM` 或自定义时区)[^2]。 #### 3. **验证时区时间函数的影响** 可以通过对比时间函数验证时区是否生效: ```sql SELECT NOW(), UTC_TIMESTAMP(); ``` - `NOW()` 返回当前会话时区时间。 - `UTC_TIMESTAMP()` 返回 UTC 时间。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值