Spring Boot+Hibernate更新Order时datetime被自动设为早3小时问题
这个问题我之前做项目时碰到过,核心是两个关键点:Hibernate的自动字段更新机制和时区配置不一致,咱们一步步来搞定:
一、为什么datetime会被自动更新?
大概率是你的Order实体类里的datetime字段被Hibernate标记为了"自动更新"字段,常见的情况有两种:
1. 误用了@UpdateTimestamp注解
如果你的实体类里给datetime字段加了@UpdateTimestamp,那Hibernate会在每次执行update操作时自动把这个字段更新为当前时间,哪怕你没在代码里修改它:
// 这种写法会导致每次更新都自动刷新datetime @UpdateTimestamp @Column(name = "datetime") private LocalDateTime datetime;
解决办法:如果这个字段只需要在插入时设置,换成@CreationTimestamp;如果完全不需要自动更新,直接去掉这个注解,同时在@Column里加上updatable = false,明确告诉Hibernate更新时不要碰这个字段:
@Column(name = "datetime", updatable = false) @Temporal(TemporalType.TIMESTAMP) private Date datetime;
2. 未设置updatable=false
就算没加自动时间戳注解,如果你没在@Column里指定updatable=false,Hibernate在生成update语句时,可能会把实体中所有非null的字段都包含进去(如果你的datetime字段在实体里有值的话),导致数据库里的字段被覆盖更新。
二、为什么时间会早3小时?
这是典型的时区不一致问题,常见场景是:
- MySQL数据库的时区是UTC(格林威治标准时间),而你的应用运行在UTC+3时区,或者反过来;
- Hibernate在处理时间字段时,自动做了时区转换,导致最终存入数据库的时间差了3小时。
解决办法:统一三方的时区配置:
1. 检查并设置MySQL时区
登录MySQL执行命令:
show variables like '%time_zone%';
如果看到time_zone是UTC,可以把它改成你需要的时区(比如UTC+3):
set global time_zone = '+3:00'; set time_zone = '+3:00';
或者修改MySQL的配置文件(my.cnf或my.ini),永久生效:
[mysqld] default-time-zone = '+3:00'
2. 配置Spring Boot应用的时区
在application.properties里添加:
# 设置Jackson序列化的时区(返回前端时的时区) spring.jackson.time-zone=GMT+3 # 设置Hibernate JDBC操作时的时区 spring.jpa.properties.hibernate.jdbc.time_zone=GMT+3
3. 在数据库连接URL里指定时区
确保你的数据源URL里加上时区参数:
spring.datasource.url=jdbc:mysql://localhost:3306/your_db_name?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B3
三、额外排查点
如果你用了Spring Data JPA的审计功能(比如启动类加了@EnableJpaAuditing),检查一下datetime字段是不是被@LastModifiedDate这类审计注解标记了,如果是,不需要的话去掉即可。
按照上面的步骤调整后,再测试更新操作,应该就能解决datetime自动更新和时区差的问题了。
内容的提问来源于stack exchange,提问作者Bora

