针对数据库逻辑删除操作简单实现方案

数据库逻辑删除

定义

逻辑删除是指在删除数据库的某条记录时,并不是真正的将该条记录删除,而是通过某个字段来标识其状态为“删除”,在接下来的查询等操作时,根据此字段来过滤调被删除的记录。

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进行删除操作。

posted @ 2022-12-07 16:28  plum_wink  阅读(980)  评论(0编辑  收藏  举报