MyBatis-Plus 是开发里的一把好手,省了不少重复代码。今天咱们聊两个实用功能:逻辑删除 和批量操作。逻辑删除能让我们优雅地"删"数据,批量操作能高效处理一堆记录。直接上干货,带代码走起!
1. MyBatis-Plus 的逻辑删除
1.1 逻辑删除是啥?
逻辑删除不是真把数据从数据库删掉,而是加个标记,比如有个字段 deleted
,0 表示正常,1 表示已删除。查数据时自动过滤掉 deleted=1
的,删除时改改标记就行。这样既能保留历史数据,又不影响正常查询。
1.2 配置逻辑删除
MP 的逻辑删除开箱即用,先得做点准备。
表结构 :假设有个 user
表,字段是 id
、username
、age
、deleted
(int 类型,0=正常,1=删除)。
实体类 :加个 @TableLogic
注解:
java
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("user")
public class User {
private Long id;
private String username;
private Integer age;
@TableLogic
private Integer deleted; // 逻辑删除字段
}
全局配置 (可选):在 application.yml
里设置默认值:
yaml
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除字段
logic-delete-value: 1 # 删除时的值
logic-not-delete-value: 0 # 未删除时的值
如果加了全局配置,实体类里 @TableLogic
可以不写,默认走全局设置。
Mapper :照旧继承 BaseMapper
:
java
public interface UserMapper extends BaseMapper<User> {
}
1.3 实战:逻辑删除
逻辑删除用的是 deleteById
或 delete
方法,MP 会自动把它转成 UPDATE
操作。
单个删除:
java
@SpringBootTest
class LogicDeleteTest {
@Autowired
private UserMapper userMapper;
@Test
void testDeleteById() {
userMapper.deleteById(1L);
System.out.println("ID=1 的用户被逻辑删除了!");
}
}
跑完后,数据库里这条记录的 deleted
变成 1,但数据还在。MP 实际执行的 SQL 是:
sql
UPDATE user SET deleted=1 WHERE id=1 AND deleted=0
条件删除:
java
@Test
void testDeleteByCondition() {
userMapper.delete(new QueryWrapper<User>().eq("age", 25));
System.out.println("25岁的都被逻辑删了!");
}
SQL 变成:
sql
UPDATE user SET deleted=1 WHERE age=25 AND deleted=0
1.4 查询时自动过滤
逻辑删除的好处是查询时自动带上 deleted=0
的条件:
java
@Test
void testSelect() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
执行的 SQL 是:
sql
SELECT id, username, age, deleted FROM user WHERE deleted=0
删掉的数据不会出现在结果里,省得你手动加条件。
1.5 想查已删除的怎么办?
如果真想查 deleted=1
的,得自定义 SQL:
java
@Select("SELECT * FROM user WHERE deleted=1")
List<User> selectDeleted();
或者用 Wrapper
跳过逻辑删除:
java
@Test
void testSelectWithDeleted() {
List<User> users = userMapper.selectList(new QueryWrapper<User>().eq("deleted", 1));
users.forEach(System.out::println);
}
1.6 注意点
- 逻辑删除只对 MP 自带方法生效,自定义 SQL 得自己处理
deleted
。 - 配置好字段后,MP 会帮你改
INSERT
和UPDATE
,自动填默认值(比如插入时deleted=0
)。
明白了,你想要的是基于 MyBatis-Plus 实现逻辑删除的具体优点和缺点。那我就结合 MyBatis-Plus 的特性,重新梳理一下逻辑删除的优缺点,聚焦在工具层面的实际体验。
使用 MyBatis-Plus 实现逻辑删除的优点
- 开箱即用,配置简单
MyBatis-Plus 提供了 @TableLogic 注解和全局配置(logic-delete-field 等),几行代码就能启用逻辑删除。不用自己手写 SQL 的 UPDATE 和过滤逻辑,开发效率直接拉满。 - 自动过滤已删除数据
调用 selectList、selectById 等内置方法时,MP 会自动在 SQL 中加上 WHERE deleted=0(或其他配置的未删除值),业务代码零改动,查询结果天然干净。 - 默认值自动填充
插入数据时,MP 会自动为 deleted 字段填入未删除值(比如 0),更新时也能智能处理,减少手动维护字段的麻烦。 - 统一性强
通过全局配置,所有表可以共用一套逻辑删除规则(比如字段名和删除值),团队协作时风格一致,维护成本低。 - 与物理删除无缝切换
如果某张表不需要逻辑删除,去掉 @TableLogic 或调整配置,MP 就能切换成物理删除,灵活性很强。
使用 MyBatis-Plus 实现逻辑删除的缺点
- 自定义 SQL 不受控
逻辑删除只对 MP 的内置方法(如 deleteById、selectList)生效,手写的 @Select 或 @Update SQL 不会自动加 deleted 条件,得自己处理,容易遗漏。 - 全局配置可能不够灵活
如果项目里不同表需要不同的逻辑删除字段或值(比如有的用 is_deleted,有的用 deleted),全局配置就显得鸡肋,得在每张表单独加 @TableLogic 覆盖,略显繁琐。 - 性能隐患未解决
MP 只是实现了逻辑删除的标记和过滤,数据长期积累导致的表膨胀问题它管不了,得开发者自己搞定时清理或归档,工具本身没提供解决方案。 - 调试复杂性增加
因为删除操作被转成 UPDATE,日志里看到的 SQL 不像物理删除那么直观,排查问题时可能得多看几眼字段状态。 - 字段依赖强
逻辑删除依赖实体类里的 deleted 字段,如果表结构没加这个字段或者字段名不一致,MP 的逻辑删除就失效,得严格对齐数据库设计。