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

JPA使用@Version时如何实现软删除?版本字段同步问题求解

带@Version的JPA实体实现软删除的正确方案

问题根源

你猜的没错,报错核心原因是:Hibernate处理乐观锁(@Version)时会校验操作的版本一致性,但最初的@SQLDelete语句既没把version作为更新条件,也没更新version字段,导致乐观锁验证失败,抛出数据完整性异常。

你后来修改的@SQLDelete虽然加了version条件,但没更新version值,会导致依赖版本号的其他操作无法感知这次软删除的变更,进而引发并发问题。

正确实现方式

1. 修改实体类的注解与字段映射

需要同时完成三件事:

  • 在@SQLDelete中更新version字段(自增1),并保留version作为where条件
  • 添加@Where注解,让所有默认查询自动过滤已软删除的记录
  • 确保isDeleted字段的映射正确

修改后的实体类代码:

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
// 软删除时更新is_deleted和version,同时用student_id和version做乐观锁校验
@SQLDelete(sql = "update student set is_deleted=true, version=version+1 where student_id=? and version=?")
// 默认查询排除已软删除的记录
@Where(clause = "is_deleted = false")
public class Student {
    
    @Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
    private String studentId;

    @Column(nullable = false, columnDefinition = "VARCHAR(255)")
    private String name;

    @Column(name = "age")
    private Integer age;

    @Version
    private Integer version;

    private boolean isDeleted;
}

2. 服务层代码无需修改

你现有的deleteSt方法保持不变即可:

@Transactional
public String deleteSt(String id) {
    sr.deleteById(id);
    return "Deleted";
}

为什么这么做?

  • 更新version字段:软删除本质是一次更新操作,必须更新version值,这样其他依赖version做乐观锁的操作能感知到这条数据已被修改,避免并发冲突
  • where条件带version:确保只有当前版本的数据会被软删除,符合乐观锁的校验逻辑,防止并发情况下的误操作
  • @Where注解:让JPA的默认查询(比如findById、findAll)自动排除已软删除的记录,不需要在每个查询里手动加过滤条件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 03:01:16