针对数据库逻辑删除操作简单实现方案
数据库逻辑删除
定义
逻辑删除是指在删除数据库的某条记录时,并不是真正的将该条记录删除,而是通过某个字段来标识其状态为“删除”,在接下来的查询等操作时,根据此字段来过滤调被删除的记录。
java中常用的orm框架有mybatis和hibernate,下面说下两种框架在使用中简单的逻辑删除操作。
mybatis-plus
SpringBoot 配置方式:
- application.yml 加入配置(如果你的默认值和mp默认的一样,该配置可无):
mybatis-plus:
global-config:
db-config:
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
对于逻辑删除拦截器的bean的注入方式
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfiguration {
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}
-
实体类字段上加上
@TableLogic
注解@TableLogic private Integer deleted;
-
效果: 使用mp自带方法删除和查找都会附带逻辑删除功能 (自己写的xml不会)
example 删除时 update user set deleted=1 where id =1 and deleted=0 查找时 select * from user where deleted=0
附件说明
- 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。
- 当进行逻辑删除后,再通mp的api进行数据查询时会自动过滤掉已经
删除(逻辑删除)
掉的数据。
如: 员工离职,账号被锁定等都应该是一个状态字段,此种场景不应使用逻辑删除。
- 若确需查找删除数据,如老板需要查看历史所有数据的统计汇总信息,请单独手写sql。
注意:通过mapper文件写的sql语句不会通过以上方式自动添加逻辑删除条件
hibernate
在hibernate中有@SQLDelete和@Where注解也可以帮我们实现逻辑删除操作。
在entity中使用这两个注解,如图所示
@Data
@Entity
@Table(name = "CL_BIZ_APPLY")
@SQLDelete(sql = "update CL_BIZ_APPLY set DELETE_FLAG = 0 where PK_CLBIZAPPLY = ?")
@SQLDeleteAll(sql = "update CL_BIZ_APPLY set DELETE_FLAG = 0 where PK_CLBIZAPPLY = ?")
@Where(clause = "DELETE_FLAG = 1")
@EntityListeners(AuditingEntityListener.class)
public class ClBizApplyEntity implements Serializable {
/**
* ID号,主键
* nullable : false
* default : null
*/
@Id
@SequenceGenerator(name = "SEQ_CLBIZAPPLY_PKCLBIZAPPLY", sequenceName = "SEQ_CLBIZAPPLY_PKCLBIZAPPLY", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_CLBIZAPPLY_PKCLBIZAPPLY")
@Column(name = "PK_CLBIZAPPLY", nullable = true, length = 16)
private Long pkClbizapply;
/**
* 删除标记
* nullable : true
* default : null`
* 0:已删除 1:未删除 2:彻底删除
*/
@Column(name = "DELETE_FLAG", nullable = true, length = 2)
private String deleteFlag;
/**
* 创建时间
* nullable : true
* default : sysdate
*/
@Column(name = "CREATE_TIME", nullable = true,updatable = true)
@CreatedDate
private java.util.Date createTime;
/**
* 修改时间
* nullable : true
* default : null
*/
@Column(name = "UPDATE_TIME", nullable = true)
@LastModifiedDate
private java.util.Date updateTime;
}
在sql中写上删除的时候的SQL语句,到调用delete方法的时候,hibernate将自动执行该语句将实现软删除。
下面将展示效果:
首先数据库中创建一条删除状态为1(未删除)的数据
运行程序进行查询
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class OracleTest {
@Autowired
private ClBizApplyDao clBizApplyDao;
@Test
public void getBefore(){
System.out.println("entity:" + this.clBizApplyDao.findById(408L));
}
}
查询结果
Hibernate: select clbizapply0_.pk_clbizapply as pk_clbizapply1_0_0_, clbizapply0_.create_time as create_time2_0_0_, clbizapply0_.delete_flag as delete_flag3_0_0_, clbizapply0_.update_time as update_time4_0_0_ from cl_biz_apply clbizapply0_ where clbizapply0_.pk_clbizapply=? and ( clbizapply0_.DELETE_FLAG = 1)
entity:Optional[ClBizApplyEntity(pkClbizapply=408, deleteFlag=1, createTime=2022-02-22 13:54:21.0, updateTime=2022-03-28 13:29:42.0)]
此时的查询操作会自动拼接我们在@Where注解提供的sql片段。
执行逻辑删除操作
@Transactional(rollbackFor = Exception.class)
@Override
public void deleteFlag(Long id) {
this.clBizApplyDao.deleteById(id);
}
执行结果
Hibernate: select clbizapply0_.pk_clbizapply as pk_clbizapply1_0_0_, clbizapply0_.create_time as create_time2_0_0_, clbizapply0_.delete_flag as delete_flag3_0_0_, clbizapply0_.update_time as update_time4_0_0_ from cl_biz_apply clbizapply0_ where clbizapply0_.pk_clbizapply=? and ( clbizapply0_.DELETE_FLAG = 1)
Hibernate: update CL_BIZ_APPLY set DELETE_FLAG = 0 where PK_CLBIZAPPLY = ?
hibernate删除只是操作了@SQLDelete中的SQL语句。因为hibernate删除前会先执行一次查询操作,所以显示了两个sql。
再次执行上面的查询语句,查询结果
Hibernate: select clbizapply0_.pk_clbizapply as pk_clbizapply1_0_0_, clbizapply0_.create_time as create_time2_0_0_, clbizapply0_.delete_flag as delete_flag3_0_0_, clbizapply0_.update_time as update_time4_0_0_ from cl_biz_apply clbizapply0_ where clbizapply0_.pk_clbizapply=? and ( clbizapply0_.DELETE_FLAG = 1)
entity:Optional.empty
操作后查询出的数据为空,表明已经删除成功。
以上就是两种框架的逻辑删除简单流程。
个人感觉在开发过程中,针对于逻辑删除使用这种框架提供的注解方式去实现有点不好维护,建议手写sql进行删除操作。