如何在不修改实体的情况下触发JPA的PreUpdate回调?
问题描述
我发现JPA的特性是:只有当实体发生变更时,调用save()才会触发PreUpdate回调。我想要实现的是:从数据库中查询实体后,仅通过PreUpdate来更新日期字段。
现有实体类代码如下:
@NoArgsConstructor @AllArgsConstructor @Data @DynamicUpdate @Entity @Table(name = "Table") public class TableEntity { @Id @GeneratedValue(generator = "UUID") @GenericGenerator( name = "UUID", strategy = "uuid2" ) @Column(name = "Id", nullable = false) private String id; @Column(name = "Something") private String something; @Column(name = "Fecha") private LocalDateTime fecha; @PreUpdate private void update() { setFecha(LocalDateTime.now()); } }
Repository是无自定义方法的空仓库,服务层自动注入该Repository。
目前的情况是:修改实体属性后调用save(),PreUpdate会被触发;但如果直接查询实体后调用save()且不修改任何属性,PreUpdate不会触发。请问有没有办法在不修改实体其他属性的情况下触发PreUpdate?
解决方案
这里提供几种可行的方案:
手动触发实体脏状态
查询到实体后,手动修改任意一个属性再恢复原值,让JPA认为实体发生了变更,从而触发PreUpdate。示例代码:TableEntity entity = tableRepository.findById("your-id").orElseThrow(); // 临时修改并恢复属性,触发脏状态 String tempValue = entity.getSomething(); entity.setSomething(tempValue); tableRepository.save(entity);这种方法简单直接,不需要修改实体类结构,但略显取巧。
添加@Version乐观锁字段
在实体类中添加@Version注解的版本字段,JPA在执行save()时,即使其他属性没有变化,也会更新版本号,从而触发PreUpdate回调。同时还能实现乐观锁,避免并发更新问题。修改后的实体类:@NoArgsConstructor @AllArgsConstructor @Data @DynamicUpdate @Entity @Table(name = "Table") public class TableEntity { // 原有属性... @Version @Column(name = "version") private Integer version; @PreUpdate private void update() { setFecha(LocalDateTime.now()); } }这是比较规范的做法,推荐使用。
直接执行更新语句
如果只是需要更新日期字段,可以跳过实体回调,直接在Repository中定义JPQL更新方法:public interface TableRepository extends JpaRepository<TableEntity, String> { @Modifying @Query("UPDATE TableEntity t SET t.fecha = :now WHERE t.id = :id") void updateFechaById(@Param("id") String id, @Param("now") LocalDateTime now); }使用时直接调用这个方法即可,不需要查询实体,效率更高,也不需要依赖
PreUpdate回调。
内容的提问来源于stack exchange,提问作者David_Garcia
相关产品推荐
相关产品推荐

