MyBatisPlus逻辑删除实现

wen java案例 2

本文目录导读:

MyBatisPlus逻辑删除实现

  1. 核心原理
  2. 实现步骤
  3. 特殊操作
  4. 注意事项
  5. 完整示例

MyBatis-Plus 的逻辑删除是一种数据管理策略,它通过标记数据为“已删除”状态,而不是真正从数据库中物理删除记录,这种方式可以保留历史数据,便于数据恢复和审计。

下面详细介绍 MyBatis-Plus 逻辑删除的实现方法:

核心原理

MyBatis-Plus 在全局配置或实体类中指定一个逻辑删除字段,在执行删除操作时,自动将删除操作转换为 UPDATE 语句(设置删除标记),查询时自动添加条件过滤已删除的数据。

实现步骤

数据库表设计

在表中添加一个逻辑删除字段,通常命名为 deletedis_deleteddel_flag

CREATE TABLE user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50),
    email VARCHAR(100),
    deleted INT DEFAULT 0 COMMENT '逻辑删除标记:0-未删除,1-已删除'
);

全局配置(推荐方式)

在 Spring Boot 的配置文件 application.ymlapplication.properties 中配置:

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

或者在 application.properties 中:

mybatis-plus.global-config.db-config.logic-delete-field=deleted
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

实体类配置(局部方式)

在实体类的逻辑删除字段上添加 @TableLogic 注解:

@Data
@TableName("user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private String email;
    @TableLogic
    private Integer deleted;
    // 或者自定义值
    // @TableLogic(value = "0", delval = "1")
    // private Integer deleted;
    // getter/setter 省略
}

使用效果

配置完成后,MyBatis-Plus 会自动处理逻辑删除相关操作:

// 1. 删除操作 - 自动转为 UPDATE
userMapper.deleteById(1L);
// 实际执行的 SQL: UPDATE user SET deleted=1 WHERE id=1 AND deleted=0
// 2. 查询操作 - 自动添加过滤条件
List<User> users = userMapper.selectList(null);
// 实际执行的 SQL: SELECT * FROM user WHERE deleted=0
// 3. 更新操作 - 也会自动过滤已删除数据
User user = new User();
user.setId(1L);
user.setName("updated");
userMapper.updateById(user);
// 实际执行的 SQL: UPDATE user SET name='updated' WHERE id=1 AND deleted=0

特殊操作

查询已删除数据(不自动过滤)

// 方式一:使用 Wrapper 忽略逻辑删除
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("id", 1L);
List<User> users = userMapper.selectList(wrapper);
// 这样查询会包含已删除的数据
// 方式二:使用 Mapper 的 selectByMap
Map<String, Object> map = new HashMap<>();
map.put("deleted", 1);  // 查询已删除的数据
List<User> users = userMapper.selectByMap(map);

物理删除(真正删除)

// 使用 Mapper 的 delete 方法(与逻辑删除无关)
userMapper.deleteById(1L);  // 这仍然是逻辑删除
// 如果要物理删除,需要使用自定义 SQL
@Delete("DELETE FROM user WHERE id = #{id}")
int physicalDeleteById(@Param("id") Long id);

恢复已删除数据

// 直接通过更新操作恢复
User user = new User();
user.setId(1L);
user.setDeleted(0);  // 设置未删除
userMapper.updateById(user);  // 注意:updateById 也会过滤 deleted=0,这里需要特殊处理
// 最佳实践:使用自定义 SQL 恢复
@Update("UPDATE user SET deleted=0 WHERE id=#{id}")
int restoreById(@Param("id") Long id);

注意事项

  1. 数据类型一致性:逻辑删除字段的类型需要与配置的值类型匹配(常用 Integer、Boolean、String)。

  2. 唯一索引问题:逻辑删除可能导致唯一索引冲突,解决方案:

    • 使用联合唯一索引(包含删除标记字段)
    • 使用软删除代替硬删除的唯一约束检查
  3. 性能影响:大量已删除数据会影响查询性能,建议定期物理清理。

  4. 复杂查询:在多表关联查询时,需要手动处理逻辑删除条件。

  5. 版本兼容性:不同 MyBatis-Plus 版本配置方式可能略有不同,参考对应版本文档。

完整示例

// 实体类
@Data
@TableName("user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private String email;
    @TableLogic
    private Integer deleted;
}
// Service
@Service
public class UserService extends ServiceImpl<UserMapper, User> {
    // 逻辑删除(自动转换)
    public boolean deleteUser(Long id) {
        return removeById(id);
    }
    // 物理删除
    @Transactional
    public boolean physicalDelete(Long id) {
        return baseMapper.physicalDeleteById(id) > 0;
    }
    // 恢复用户
    @Transactional
    public boolean restoreUser(Long id) {
        return baseMapper.restoreById(id) > 0;
    }
}
// Mapper
@Mapper
public interface UserMapper extends BaseMapper<User> {
    @Delete("DELETE FROM user WHERE id = #{id}")
    int physicalDeleteById(@Param("id") Long id);
    @Update("UPDATE user SET deleted=0 WHERE id=#{id}")
    int restoreById(@Param("id") Long id);
}

通过以上配置,MyBatis-Plus 的逻辑删除功能就可以正常工作了,这种方式既保留了数据完整性,又提供了灵活的查询和控制能力。

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