hibernate 当Entity类使用@Version时,我们可以在JPA中执行软删除吗?

z3yyvxxp  于 2023-08-06  发布在  其他
关注(0)|答案(2)|浏览(226)

当我尝试在我的实体上执行软删除时,我得到以下错误:
org.springframework.dao.DataIntegrityViolationException:无法删除:[study.study.entity.Student#e4a860d5-8dd0-4abe-b218-76672627e6b0]; SQL [update student set is_deleted=true where student_id=?]; nested exception is org.hibernate.exception.DataException:无法删除:[study.study.entity.Student#e4a860d5-8dd0-4abe-b218-76672627e6b0]\n\达特org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException
下面是我的Entity类:

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@SQLDelete(sql="update student set is_deleted=true where student_id=?")
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;
}

字符串
这是我的服务方式

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

  • 我在想,因为我正在使用本机SQL查询更新(而不是实际删除)学生实体,所以本机SQL查询无法更新版本字段,因此JPA抛出错误。* 如果是这样,那么我们可以处理这种情况的方法是什么?**
    编辑1:

我们可以通过以下方式实现删除:@SQLDelete(sql="update student set is_deleted=true where student_id=? and version=?").但现在的问题是,这样我们就不会更新版本字段的值,如果任何其他程序依赖于版本字段在其结束时执行更新,那么它将错过更新,因为版本字段没有更新。

8i9zcol2

8i9zcol21#

出现此问题是因为您试图使用本机SQL查询对实体执行软删除,这会阻止Hibernate正确处理实体版本和乐观锁定。要解决这个问题,您需要使用JPA正确实现软删除,而不需要求助于原生SQL查询。您可以通过调优代码来更新实体的isDeleted属性并让Hibernate自动更新版本来实现这一点。此外,考虑向实体添加@Where子句,以自动从常规查询中排除软删除的记录。通过这些更改,您将能够在学生实体上执行软删除,而不会出现版本问题。
下面是包含这些修复的代码版本:

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@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;
}

@Repository
public interface StudentRepository extends JpaRepository<Student, String> {
}

@Service
@Transactional
public class StudentService {

    @Autowired
    private StudentRepository studentRepository;

    public String deleteStudent(String id) {
        Optional<Student> optionalStudent = studentRepository.findById(id);
        if (optionalStudent.isPresent()) {
            Student student = optionalStudent.get();
            student.setDeleted(true);
            studentRepository.save(student);
            return "Student removed";
        } else {
            return "Student not found";
        }
    }
}

字符串

ix0qys7i

ix0qys7i2#

是的,在实体类中使用Version字段时,可以在JPA(Java Persistence API)中执行软删除。软删除是指将实体标记为已删除,而不从数据库中物理删除它。不是永久删除记录,而是更新一个特殊的标志或字段来指示实体已被“软删除”。
JPA中的Version字段通常用于乐观锁定,这有助于避免并发环境中的数据冲突。但是,您也可以利用此字段进行软删除,具体取决于您的特定使用情形。
以下是如何使用JPA和Version字段实现软删除:
1.向要用于乐观锁定的字段添加@Version注解。举例来说:

@Entity
public class YourEntity {
    // Other entity fields

    @Version
    private Long version;

    // Getter and setter methods
}

字符串
1.引入一个新的字段来指示实体是否已被删除,沿着getter和setter方法:

@Entity
public class YourEntity {
    // Other entity fields

    @Version
    private Long version;

    private boolean deleted;

    // Getter and setter methods for 'deleted'
    public boolean isDeleted() {
        return deleted;
    }

    public void setDeleted(boolean deleted) {
        this.deleted = deleted;
    }
}


1.当您要执行软删除时,不要删除实体,而是将deleted字段设置为true,并使用JPA EntityManager更新实体:

YourEntity entity = entityManager.find(YourEntity.class, entityId);
entity.setDeleted(true);
entityManager.merge(entity); // Use merge() to update the entity.


1.请确保在应用程序逻辑中适当地处理软删除实体,以便在需要时从常规查询中排除它们。
通过使用这种方法,您可以为实体维护“软删除”状态,同时仍然使用Version字段进行乐观锁定。记住要考虑软删除对应用程序行为的影响,包括如何处理查询、级联操作和潜在的数据保留策略。

相关问题