You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate软删除时如何更新updated_by与updated_date字段

解决软删除时更新updated_by和updated_date的问题

问题原因

你用@SQLDelete实现软删除时,Hibernate会直接执行你指定的UPDATE SQL,完全绕过了JPA的实体生命周期流程——这就是为什么你用@PreRemove修改实体字段后,变更不会持久化的核心原因:Hibernate根本没处理实体的状态变更,直接执行了你写的SQL语句。

推荐解决方案:JPA实体生命周期事件+@Where实现软删除

放弃@SQLDelete,改用@PreRemove结合@Where注解,既能触发实体事件更新字段,又能自动过滤已删除记录,流程更符合JPA规范,维护成本更低。

步骤1:定义实体类

给实体添加@Where注解过滤已软删数据,同时指定实体监听器:

@Entity
@Table(name = "table_name")
@Where(clause = "deleted = false") // 查询时自动过滤已删除的记录
@EntityListeners(SoftDeleteEntityListener.class)
public class YourEntity {
    @Id
    private Long id;
    private Boolean deleted = false;
    private LocalDateTime updatedDate;
    private Long updatedBy;
    // 其他业务字段
    
    // Getter & Setter
}

步骤2:编写实体监听器

在@PreRemove方法中设置软删标记、更新时间和操作用户ID:

public class SoftDeleteEntityListener {
    @PreRemove
    public void handleSoftDelete(YourEntity entity) {
        // 设置软删标记
        entity.setDeleted(true);
        // 设置更新时间
        entity.setUpdatedDate(LocalDateTime.now());
        // 从SecurityContext获取当前用户ID
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.getPrincipal() instanceof CustomUserDetails) {
            CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
            entity.setUpdatedBy(userDetails.getId()); // 替换成你项目中实际获取用户ID的逻辑
        }
    }
}

(注:CustomUserDetails是你自定义的Spring Security用户详情实现类,根据实际业务调整获取用户ID的方式即可)

步骤3:执行软删除

调用Spring Data JPA的delete()或EntityManager的remove()方法即可,JPA会自动生成包含所有更新字段的SQL:

UPDATE table_name SET deleted = ?, updated_date = ?, updated_by = ? WHERE id = ?

备选方案:保留@SQLDelete,通过Hibernate事件传递updated_by参数

如果一定要保留@SQLDelete,需要通过Hibernate的事件拦截器传递用户ID参数,但实现复杂且维护成本高,仅推荐用于特殊场景:

  1. 修改@SQLDelete语句,添加updated_by占位符:
@SQLDelete(sql = "UPDATE table_name SET deleted = true, updated_date = now(), updated_by = ? WHERE id = ?")
  1. 实现BeforeDeleteEventListener拦截删除事件,将用户ID注入SQL参数:
public class SoftDeleteParameterInjector implements BeforeDeleteEventListener {
    @Override
    public void onPreDelete(PreDeleteEvent event) {
        Object entity = event.getEntity();
        if (entity instanceof YourEntity) {
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            if (auth != null && auth.getPrincipal() instanceof CustomUserDetails) {
                Long userId = ((CustomUserDetails) auth.getPrincipal()).getId();
                // 此处需要操作Hibernate内部API修改SQL参数列表,将userId插入参数首位
                // 该实现依赖Hibernate版本,容易出现兼容性问题,需谨慎使用
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Mitch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 00:27:18