使用 Hibernate @SQLDelete 对所有实体进行软删除

Posted

技术标签:

【中文标题】使用 Hibernate @SQLDelete 对所有实体进行软删除【英文标题】:Using Hibernate @SQLDelete for Soft Delete across All Entities 【发布时间】:2012-02-03 10:33:33 【问题描述】:

我们有一个相当复杂的数据模型,并在 mysql 之上使用 Hibernate 和 Spring Data JPA。我们有一个基类,所有域对象都扩展它以最小化样板代码。我希望能够仅使用此类在我们所有的域对象中添加软删除功能。但是,@SQLDelete 需要子句中的表名:

@SQLDelete(sql="UPDATE (table_name) SET deleted = '1' WHERE id = ?")
@Where(clause="deleted <> '1'")

有人知道一种方法来概括 SQLDelete 语句并允许扩展域对象填充它们自己的表名吗?

【问题讨论】:

我们将在我们自己的 AbstractAudible 版本中使用它,它扩展了 Spring Data 的 Persistable。 【参考方案1】:

另一种方法,可能更灵活。

在实体级别创建

@MappedSuperclass
public class SoftDeletableEntity 

    public static final String SOFT_DELETED_CLAUSE = "IS_DELETED IS FALSE";

    @Column(name = "is_deleted")
    private boolean isDeleted;
    ...


更新应该是可软删除的实体

@Entity
@Where(clause = SoftDeletableEntity.SOFT_DELETED_CLAUSE)
@Table(name = "table_name")
public class YourEntity extends SoftDeletableEntity  ...

创建一个扩展 Spring 存储库的自定义接口存储库。添加软删除的默认方法。它应该作为您的存储库的基础存储库。例如

    @NoRepositoryBean
    public interface YourBaseRepository<T, ID> extends JpaRepository<T, ID> 


        default void softDelete(T entity) 

            Assert.notNull(entity, "The entity must not be null!");
            Assert.isInstanceOf(SoftDeletableEntity.class, entity, "The entity must be soft deletable!");

            ((SoftDeletableEntity)entity).setIsDeleted(true);
            save(entity);
        

        default void softDeleteById(ID id) 

            Assert.notNull(id, "The given id must not be null!");
            this.softDelete(findById(id).orElseThrow(() -> new EmptyResultDataAccessException(
                    String.format("No %s entity with id %s exists!", "", id), 1)));
        


    

注意:如果您的应用程序没有硬删除,那么您可以添加

    String HARD_DELETE_NOT_SUPPORTED = "Hard delete is not supported.";

    @Override
    default void deleteById(ID id) 
        throw new UnsupportedOperationException(HARD_DELETE_NOT_SUPPORTED);
    

    @Override
    default void delete(T entity) 
        throw new UnsupportedOperationException(HARD_DELETE_NOT_SUPPORTED);
    

    @Override
    default void deleteAll(Iterable<? extends T> entities) 
        throw new UnsupportedOperationException(HARD_DELETE_NOT_SUPPORTED);
    

    @Override
    default void deleteAll() 
        throw new UnsupportedOperationException(HARD_DELETE_NOT_SUPPORTED);
    

希望它有用。

【讨论】:

重写 delete() 并抛出错误的好方法。但是,有什么方法可以在全局级别执行这些操作,否则,我需要写入所有存储库。代码重复。【参考方案2】:

如果您使用 hibernate 和 @SQLDelete,您的问题没有简单的解决方案。但是您可以考虑使用 Spring Data 的表达式语言进行软删除的另一种方法:

@Override
@Query("select e from ##entityName e where e.deleteFlag=false")
public List<T> findAll();

//recycle bin
@Query("select e from ##entityName e where e.deleteFlag=true")
public List<T> recycleBin(); 

@Query("update ##entityName e set e.deleteFlag=true where e.id=?1")
@Modifying
public void softDelete(String id); 
//##entityName will be substituted by concrete entity name automatically.

像这样重写基础存储库。所有子存储库接口都将具有软删除能力。

【讨论】:

简单明了的解决方案,谢谢。但不要忘记更新方法或整个类的@Transactional 注释。作为几乎初学者,我花了一些时间来找出...

以上是关于使用 Hibernate @SQLDelete 对所有实体进行软删除的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate在超类中定义@Where注解

spring-data-jpa软删除方案

SQL 删除

SQL DELETE 语句:删除表中的记录语法及案例剖析

为啥这个使用 INNER JOIN 的 SQL DELETE 查询不起作用? [复制]

对使用 Spring 和 Hibernate 的 Java 日志系统感到困惑