Java案例如何实现逻辑删除?

wen java案例 58

本文目录导读:

Java案例如何实现逻辑删除?

  1. 数据库层面
  2. MyBatis-Plus 实现(推荐,最简单)
  3. 手动实现(不使用 ORM 框架)
  4. 高级技巧:自动填充删除时间
  5. 总结与最佳实践

在Java中实现逻辑删除(软删除)通常包含以下几个核心层面:数据库设计、实体类定义、MyBatis-Plus配置(常用方案)、以及查询时的自动过滤。

以下是完整的实现方案,涵盖最常用的 MyBatis-Plus 方式以及通用的手动实现方式。


数据库层面

在表中添加一个字段用于标记是否被删除,常用的字段名有 is_deleteddeleted

ALTER TABLE user 
ADD COLUMN `is_deleted` tinyint(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除标识 0-未删除 1-已删除';
  • 0:未删除(正常数据)
  • 1:已删除(逻辑删除后的数据)

MyBatis-Plus 实现(推荐,最简单)

MyBatis-Plus 内置了逻辑删除插件,只需要简单配置即可。

配置全局属性

application.ymlapplication.properties 中配置:

# application.yml
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: is_deleted  # 全局逻辑删除字段名(1.0.0+)
      logic-delete-value: 1           # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0       # 逻辑未删除值(默认为 0)

实体类添加注解

在实体类对应的字段上添加 @TableLogic 注解:

import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
@TableName("user")
public class User {
    private Long id;
    private String name;
    @TableLogic
    private Integer isDeleted; // 字段名与配置的 logic-delete-field 一致
    // getter 和 setter 省略
}

效果验证

配置完成后,MyBatis-Plus 会自动处理:

  • 删除操作

    userMapper.deleteById(1L);
    // 实际执行的 SQL:UPDATE user SET is_deleted=1 WHERE id=1 AND is_deleted=0
    // 注意:默认只会更新 id=1 且未删除的记录
  • 查询操作

    userMapper.selectById(1L);
    // 实际执行的 SQL:SELECT * FROM user WHERE id=1 AND is_deleted=0
    // 自动追加了 is_deleted=0 条件
  • 更新操作

    userMapper.updateById(user);
    // 实际执行的 SQL:UPDATE user SET ... WHERE id=? AND is_deleted=0
    // 自动限制只能更新未删除的记录

手动实现(不使用 ORM 框架)

如果你没有使用 MyBatis-Plus,可以手动在 DAO 层或 Service 层实现。

基础编码

// Service 层实现
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    // 逻辑删除
    @Override
    public void logicDelete(Long id) {
        User user = new User();
        user.setId(id);
        user.setIsDeleted(1);
        userMapper.updateById(user);
        // 等效 SQL:UPDATE user SET is_deleted = 1 WHERE id = ?
    }
    // 查询(必须加上未删除条件)
    @Override
    public User findById(Long id) {
        // 自定义查询,手动加上 is_deleted = 0
        return userMapper.selectByIdAndNotDeleted(id);
    }
}
// Mapper XML 示例
// <select id="selectByIdAndNotDeleted" resultType="User">
//     SELECT * FROM user WHERE id = #{id} AND is_deleted = 0
// </select>

关键注意事项

  • 所有查询都必须手动过滤 is_deleted = 0,遗漏会导致数据混乱。
  • 唯一约束问题:如果对字段设置了唯一约束(如邮箱、手机号),逻辑删除后再次插入相同值会冲突,解决方案有两种:
    • 唯一约束联合 is_deleted 字段(允许0有唯一,1可以重复)。
    • 删除时对唯一字段加工(email = id + '_deleted' + email)。

高级技巧:自动填充删除时间

结合 MyBatis-Plus 的自动填充功能,可以在逻辑删除时自动记录删除时间。

// 实体类增加字段
@TableField(fill = FieldFill.UPDATE)  // 或 FieldFill.INSERT_UPDATE
private LocalDateTime deleteTime;
// 自定义 MetaObjectHandler 实现
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void updateFill(MetaObject metaObject) {
        // 获取当前 is_deleted 值,如果为1(删除),则自动填充时间
        Object isDeleted = getFieldValByName("isDeleted", metaObject);
        if (isDeleted != null && (Integer) isDeleted == 1) {
            this.strictUpdateFill(metaObject, "deleteTime", LocalDateTime.now());
        }
    }
}

总结与最佳实践

步骤 说明
1 数据库添加 is_deleted 字段 类型为 tinyint,默认为 0
2 实体类添加对应字段和注解 推荐使用 MyBatis-Plus 的 @TableLogic
3 配置全局逻辑删除规则 指定已删除/未删除对应的值
4 业务层正常调用 框架自动处理 SQL 中的条件追加

建议

  • 如果项目新启动,直接使用 MyBatis-Plus 的内置逻辑删除,效率最高。
  • 如果已有复杂查询,注意检查自定义 SQL 是否也需要过滤 is_deleted 条件(可以使用 XML 中的 SQL 片段或自定义拦截器)。
  • 逻辑删除的数据仍然占用存储空间,建议定期做物理归档或清理。

这样,你的 Java 应用就能优雅地实现逻辑删除了。

抱歉,评论功能暂时关闭!