环境:SpringBoot3.4.0
1. 简介
在软件开发中,逻辑删除作为一种灵活的数据处理方式,被广泛应用于各种系统中。特别是在需要保留数据历史或防止误删除的场景下,逻辑删除显得尤为重要。
通常逻辑删除之所以被采用,主要有以下几个原因:
- 数据恢复方便,只需更新数据状态即可
- 保护数据完整性,避免因物理删除而破坏数据关联
- 满足审计和合规性要求,保留记录的存在
- 降低误操作风险,为开发者提供安全网
然而,逻辑删除也可能导致数据膨胀和查询复杂性增加等问题,因此在使用时需要权衡利弊。
本篇文章将要介绍如何使用JPA和MyBatis来实现逻辑删除的功能。
2. 实战案例
2.1 JPA逻辑删除
基于JPA的逻辑删除,这里介绍2中实现方案。
使用@SQLDelete注解
在实体类上通过该注解定义执行的SQL语句,如下示例:
@Entity
@Table(name = "t_person")
@SQLDelete(sql = "update t_person p set p.deleted = 1 where p.id = ?")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id ;
private String name ;
private Integer age ;
/**0:正常,1:删除*/
@Column(columnDefinition = "int default 0")
private Integer deleted = 0;
// getters, setters
}
Repository接口定义
public interface PersonRepository extends JpaRepository<Person, Long> {
}
单元测试
@Test
public void testDelete() {
this.personRepository.deleteById(2L) ;
}
最终执行SQL
最终执行了通过@SQLDelete配置的update语句。
使用@SoftDelete注解
@SoftDelete(
strategy = SoftDeleteType.DELETED,
columnName = "deleted",
converter = DeletedAttributeConverter.class
)
public class Person {
// 这里不需要定义deleted字段
}
默认情况下,@SoftDelete注解使用true和false表示删除与未删除。通过converter进行数据类型的转换,这里我们将默认使用的boolean类型改为0,1表示:
public class DeletedAttributeConverter
implements AttributeConverter<Boolean, Integer> {
@Override
public Integer convertToDatabaseColumn(Boolean attribute) {
return attribute == null || !attribute ? 0 : 1;
}
@Override
public Boolean convertToEntityAttribute(Integer dbData) {
return dbData == null || dbData == 0 ? Boolean.FALSE : Boolean.TRUE ;
}
}
当执行删除操作时,输出如下SQL:
图片
2.2 MyBatis逻辑删除
MyBatis的逻辑删除功能并非由它原生支持,而是由mybatis-plus提供的功能。
首先,引入mybatis-plus依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.10.1</version>
</dependency>
注意你当前的环境,不同的Spring Boot版本2/3引入的依赖包不一样。
接下来,进行如下的配置:
mybatis-plus:
global-config:
db-config:
# 全局逻辑删除字段名
logic-delete-field: deleted
# 逻辑已删除值
logic-delete-value: 1
# 逻辑未删除值
logic-not-delete-value: 0
如上定义后,通过MyBatis-Plus的接口进行删除时,将会与jpa一样,执行update语句。
实体定义:
@TableName("t_person")
public class Person {
/**0:正常,1:删除*/
private Integer deleted = 0;
}
Mapper接口定义如下:
public interface PersonMapper extends BaseMapper<Person> {
}
注意,你需要继承MyBatis-Plus的BaseMapper接口。
单元测试
@Test
public void testMyBatisDelete() {
this.personMapper.deleteById(2L) ;
}
SQL输出如下:
执行update语句更新deleted字段值。
指定标记删除字段
以上删除更新字段是根据全局配置文件中配置的字段名进行更新, 如果个别表是其它字段名时可以通过如下配置:
public class Person {
@TableLogic
private Integer state ;
}
当执行删除时,则会去更新state字段的值,如下SQL输出:
图片