如何避免MySQL timestamp四舍五入及Liquibase修改timestamp(3)报错问题
问题原因
- MySQL 对带精度的
TIMESTAMP类型有严格的默认值匹配规则:原有updated_at字段设置了无精度的默认值(比如默认的CURRENT_TIMESTAMP、'0000-00-00 00:00:00'),直接修改字段类型为timestamp(3)时,旧默认值和新类型的精度要求不兼容,因此触发1067错误。 - 你的修改逻辑本身是对的,
timestamp(3)确实可以存储毫秒级时间,避免后端传入的毫秒部分被四舍五入,问题出在变更操作没有处理原有默认值的兼容问题。
修复方案
1. 调整Liquibase变更脚本
分三步执行变更:先移除原有默认值,再修改字段类型,最后按需重新设置带精度的默认值,示例脚本如下:
<changeSet id="10" author="autho2"> <!-- 第一步:移除字段原有默认值约束 --> <dropDefaultValue tableName="user_data" columnName="updated_at"/> <!-- 第二步:修改字段为带3位毫秒精度的TIMESTAMP --> <modifyDataType columnName="updated_at" newDataType="timestamp(3)" tableName="user_data"/> <!-- 第三步:如果需要保留默认值,重新设置带精度的默认值,不需要可删除此步 --> <addDefaultValue tableName="user_data" columnName="updated_at" defaultValueComputed="CURRENT_TIMESTAMP(3)"/> </changeSet>
如果你的字段原本不允许为NULL,可根据业务需求在modifyDataType时补充NULL/NOT NULL声明。
2. 适配实体类定义
为了保证JPA层面和数据库类型匹配,建议补充@Column的精度声明:
@Temporal(TemporalType.TIMESTAMP) @Column(name = "updated_at", columnDefinition = "timestamp(3)") private Date updatedAt;
如果使用JDK 8及以上版本,替换java.util.Date为java.time.Instant/java.time.LocalDateTime可以避免时区和精度序列化的额外问题,无需再加@Temporal注解。
3. 验证效果
变更执行完成后,传入2021-08-11T21:59:59.999Z即可完整存储毫秒部分,不会再被四舍五入为下一分钟。
内容的提问来源于stack exchange,提问作者Catalina
相关产品推荐
相关产品推荐

