Spring+MySQL项目datetime字段增改时数据截断异常排查
问题原因分析与解决方案
兄弟,我之前踩过几乎一模一样的坑!结合你的配置细节,这个问题本质是时区不匹配+MySQL 5.7严格模式共同导致的——看起来是空值错误,实际是日期在跨时区转换时出了问题,被MySQL当成无效值截断了。
为什么会出现这个“假空值”错误?
- MySQL 5.7的严格模式:MySQL 5.7默认启用了
STRICT_TRANS_TABLES严格模式,一旦接收到不符合datetime格式的数值,就会触发Data truncation错误,而不是像旧版本那样自动修正或忽略。 - 时区不匹配导致的日期转换异常:你的JVM时区设为
Europe/Istanbul,数据库时区是GMT+3,但mysql-connector-java 5.1.x版本不会自动同步这些时区。当Hibernate把Java的Date对象传给JDBC驱动时,驱动没有用正确的时区转换,导致最终传递给MySQL的datetime值变成了无效格式(比如因为夏令时偏移导致的日期范围异常),MySQL直接把这个无效值判定为空字符串,从而抛出你看到的错误。
具体解决方案(按优先级排序)
1. 修正JDBC URL的时区参数(最关键)
对于mysql-connector-java 5.1.x版本,必须在JDBC连接URL中显式指定serverTimezone参数,确保和JVM、数据库的时区一致。两种可选写法:
- 用JVM设置的时区:
jdbc:mysql://localhost:3306/your_database?serverTimezone=Europe/Istanbul&useSSL=false - 直接用数据库的GMT+3时区(注意URL中
+要转成%2B):jdbc:mysql://localhost:3306/your_database?serverTimezone=GMT%2B3&useSSL=false
这个参数会强制JDBC驱动在转换日期时使用指定时区,避免出现无效的datetime值。你之前更新驱动无效,大概率是没加这个参数。
2. 验证并调整MySQL的严格模式(可选)
如果第一步解决不了,可以检查MySQL的sql_mode设置:
- 登录MySQL执行命令查看当前模式:
SELECT @@sql_mode; - 如果结果包含
STRICT_TRANS_TABLES或STRICT_ALL_TABLES,可以临时关闭(重启MySQL后失效):
不过不推荐长期关闭严格模式,它是MySQL 5.7的安全默认配置,能避免很多数据不一致问题。SET GLOBAL sql_mode = 'NO_ENGINE_SUBSTITUTION'; SET SESSION sql_mode = 'NO_ENGINE_SUBSTITUTION';
3. 确认Hibernate的日期映射配置
检查你的TicketDTO中日期字段的注解,确保映射正确:
import java.util.Date; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Column; // ... @Temporal(TemporalType.TIMESTAMP) @Column(name = "CREATION_DATE", nullable = false) private Date createdOn; // ...
确保@Temporal类型和数据库的datetime字段匹配,同时字段没有被错误设置为nullable = false但实际传递了无效值(不过你说代码里已经赋值了,这个大概率没问题)。
内容的提问来源于stack exchange,提问作者esat akacık
相关产品推荐
相关产品推荐

