使用JPA的getById+save更新实体时updatedtimestamp未更新是什么原因?
问题根因
核心是JPA生成UPDATE语句的规则和MySQLON UPDATE CURRENT_TIMESTAMP的触发规则不匹配导致的:
- MySQL的
CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP自动更新触发条件是:执行更新SQL时,该字段没有被显式赋值,且当前行的数据确实发生了变更,数据库才会自动将该字段更新为当前时间。 - 通过
getById查询到完整实体后直接调用save()时,JPA默认生成的UPDATE语句会把实体的所有字段都包含到SET子句中,查询出来的实体已经携带了updatedtimestamp的旧值,最终生成的SQL结构如下:
update 表名 set title = ?, updatedtimestamp = 旧时间值, 其他所有字段 = 对应旧值 where id = ?
此时相当于主动给updatedtimestamp字段赋值为旧值,MySQL会优先使用传入的字段值,不会触发自动更新逻辑。
而自定义UPDATE语句里只显式修改了title字段,没有对updatedtimestamp做任何赋值,自然满足数据库自动更新的触发条件,所以时间可以正常更新。
可行解决方案
- 方案1:给对应实体类添加
@DynamicUpdate注解
该注解会开启JPA的动态更新逻辑,生成UPDATE语句时仅包含被修改过的字段,当前场景中只有title字段发生变更,最终生成的UPDATE语句只会set title = ?,不会携带updatedtimestamp的旧值,即可触发数据库自动更新。 - 方案2:给实体类的
updatedtimestamp字段添加updatable = false配置
修改字段的@Column注解为@Column(updatable = false),告知JPA该字段不参与更新操作,生成UPDATE语句时会自动忽略该字段,同样可以触发数据库的自动更新规则。 - 方案3:改用JPA审计能力自动维护更新时间
不需要依赖数据库的ON UPDATE规则,给updatedtimestamp字段添加@LastModifiedDate注解,同时给实体类添加@EntityListeners(AuditingEntityListener.class)、启动类添加@EnableJpaAuditing注解,JPA会在实体更新时自动赋值最新时间,适配所有更新场景。
内容的提问来源于stack exchange,提问作者mozzi
相关产品推荐
相关产品推荐

