JPA @SoftDelete 实现逻辑删除

813 阅读1分钟

版本

  • jpa maven
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
  <version>3.3.1</version>
</dependency>
  • springboot 版本:3.3.1

简单使用

只需在实体类上@SoftDelete 即可实现逻辑删除
例如:

@SoftDelete
public class Student {
// 省略。。。。
}

默认配置使用 DELETED策略,并作为布尔值存储在 deleted字段中。

@SoftDelete 的定义

@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Incubating
public @interface SoftDelete {
    String columnName() default "";

    SoftDeleteType strategy() default SoftDeleteType.DELETED;

    Class<? extends AttributeConverter<Boolean, ?>> converter() default UnspecifiedConversion.class;

    public interface UnspecifiedConversion extends AttributeConverter<Boolean, Object> {
    }
}

columnName 为逻辑删除字段列名,converter 的一个数据库存在字段值到表示删除的转换器,比如如果我们想让1表示已删除0表示未删除可以用内置的NumericBooleanConverter 转换器。

进阶

自定义converter

只是使用0和1表示删除状态无法满足唯一索引的应用场景,我们可以使用删除时间表示删除状态,这时我们就需要自定义converter,示例:

package com.breeze.jpa.extension.converter;

import jakarta.persistence.AttributeConverter;

/**
 * 用于软删除
 * @author fan
 * @date 2024/8/6
 */
public class TimestampBooleanConverter implements AttributeConverter<Boolean,Long> {
    @Override
    public Long convertToDatabaseColumn(Boolean aBoolean) {
        return Boolean.TRUE.equals(aBoolean) ? System.currentTimeMillis() : 0L;
    }

    @Override
    public Boolean convertToEntityAttribute(Long aLong) {
        return aLong != null && aLong > 0L;
    }
}

这样当执行查询操作时jpa会通过调用convertToDatabaseColumn方法获取未删除状态对应的数据库字段存储值,对应是0,添加过滤条件where f1_0.delete_at=0。删除时也调用convertToDatabaseColumn传入true返回当前时间戳 例如:

update foo set delete_at=1725809750120 where id=? and delete_at=0 and version=?

示例代码地址

fan/jpa-demo (gitee.com)