Hibernate与MariaDB仅以秒精度存储时间戳?存Java Date遇唯一键冲突
这个问题我之前也碰到过,核心原因是Java Date的毫秒精度和数据库字段的精度不匹配导致的。
为什么会出现这个情况?
你用的new Date(1518458441039)和new Date(1518458441102)这两个对象,毫秒数不同,但对应的日期字符串到秒都是2018-02-12 14:00:41。如果你的MariaDB字段是默认的DATETIME类型(不带精度后缀),它只支持秒级精度,Hibernate在存储时会自动截断毫秒部分,导致两个不同的Date最终存成同一个值,触发唯一约束报错:
11:09:59.540 [main] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - (conn=502) Duplicate entry '2018-02-12 14:00:41' for key 'UK_plwo79yqbhw7h0yuxbrg5ru7q'
javax.persistence.PersistenceException: org.hibernate.exception.Co...
解决步骤
1. 修改数据库字段精度
首先要确保MariaDB的字段支持毫秒精度。MariaDB 10.1.2及以上版本支持带小数秒的DATETIME类型,你需要把字段改成:
ALTER TABLE your_table MODIFY COLUMN your_date_column DATETIME(3) UNIQUE;
这里(3)表示保留3位小数,也就是毫秒级精度;如果需要更高的微秒精度,可以用DATETIME(6)。
2. 同步Hibernate映射配置
接下来要让Hibernate知道字段的精度,避免截断:
- 注解方式:在实体类的Date字段上添加
@Column指定columnDefinition:
@Column(name = "your_date_column", columnDefinition = "DATETIME(3)", unique = true) private Date yourDateField;
- XML映射方式:在对应的字段配置里指定类型:
<property name="yourDateField" column="your_date_column" type="timestamp"> <column name="your_date_column" sql-type="DATETIME(3)" unique="true"/> </property>
3. (可选)改用Java 8+的时间类型
推荐使用Java 8引入的LocalDateTime代替旧的Date类,它的API更清晰,也能更好地和数据库的精度匹配。需要确保你的Hibernate版本支持Java 8(比如Hibernate 5.2+),然后配置如下:
@Column(name = "your_date_column", columnDefinition = "DATETIME(3)", unique = true) private LocalDateTime yourDateField;
这样存储时会完整保留毫秒信息,不会出现截断问题。
内容的提问来源于stack exchange,提问作者spierepf

