1. SpringBoot3与MybatisPlus删除操作概述
在SpringBoot3项目中整合MybatisPlus进行数据库删除操作,是日常开发中最基础却最容易踩坑的环节。作为持久层框架的黄金搭档,MybatisPlus在SpringBoot3环境下提供了多种灵活的删除方式,从简单的根据ID删除到复杂的条件删除,每种方式都有其适用场景和实现细节。
我经历过不少项目,发现很多团队在使用delete操作时存在三大误区:一是过度依赖物理删除导致数据不可追溯;二是批量删除时不做事务控制;三是忽略MP的乐观锁机制在删除场景的应用。本文将结合实战经验,带你系统掌握MybatisPlus的删除操作精髓。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础环境搭建与配置
2.1 依赖引入关键点
在pom.xml中引入依赖时,需要特别注意版本兼容性问题。SpringBoot3要求MybatisPlus版本至少为3.5.3+:
xml复制<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
注意:千万不要同时引入mybatis和mybatis-plus的starter,这会导致类冲突。我曾在一个紧急项目中因为这个问题排查了2小时。
2.2 数据源配置陷阱
在application.yml中配置数据源时,HikariCP连接池的参数需要根据删除操作特点调整:
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
为什么这样配置?因为批量删除操作往往需要更长的连接占用时间,默认的30秒超时可能导致操作中断。但也要注意不要设置过大,否则连接泄露时会影响整个系统。
3. Mapper层删除操作详解
3.1 基础删除方法
MybatisPlus在Mapper接口中提供了多种删除方法,最常用的有:
java复制// 按ID删除
int deleteById(Serializable id);
// 按条件删除
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 批量删除
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
实际项目中我推荐使用deleteById和delete方法组合。曾经有个电商项目,误用deleteBatchIds删除10万条数据导致数据库连接池耗尽,后来改用分页+delete方式解决。
3.2 条件构造器实战
复杂删除条件需要使用QueryWrapper或LambdaQueryWrapper:
java复制// 传统写法
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("status", 0)
.lt("create_time", LocalDateTime.now().minusMonths(6));
// Lambda写法
LambdaQueryWrapper<User> lambdaWrapper = Wrappers.lambdaQuery();
lambdaWrapper.eq(User::getStatus, 0)
.lt(User::getCreateTime, LocalDateTime.now().minusMonths(6));
userMapper.delete(wrapper);
踩坑提醒:Wrapper条件字段名写错不会编译报错,只会在运行时抛出异常。建议使用Lambda方式避免这种问题。
4. 高级删除场景处理
4.1 逻辑删除实现
现代项目更推荐逻辑删除而非物理删除。首先在实体类添加注解:
java复制@TableLogic
private Integer deleted;
然后在application.yml中配置:
yaml复制mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted
logic-not-delete-value: 0
logic-delete-value: 1
注意点:逻辑删除字段不要用基本类型boolean,因为MP无法区分未设置值和false。我遇到过使用boolean导致查询条件错误的问题。
4.2 批量删除优化
处理大批量删除时,建议采用分批次处理:
java复制public void batchDelete(List<Long> ids) {
List<List<Long>> partitions = Lists.partition(ids, 200);
partitions.forEach(partition -> {
userMapper.deleteBatchIds(partition);
// 每批处理完稍作停顿
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
这个技巧在用户数据清理场景特别有用,可以避免单次事务过大导致数据库锁表。
5. 事务与性能考量
5.1 事务控制要点
删除操作必须放在事务中,但要注意事务传播行为:
java复制@Transactional(rollbackFor = Exception.class)
public void deleteUserWithRelatedData(Long userId) {
// 删除用户
userMapper.deleteById(userId);
// 删除关联数据
userAddressMapper.delete(new LambdaQueryWrapper<UserAddress>()
.eq(UserAddress::getUserId, userId));
}
常见错误是忘记在Service方法上加@Transactional,导致部分删除成功部分失败。我在代码审查时至少发现过5次这类问题。
5.2 性能监控方案
对于关键删除操作,建议添加监控:
java复制@Around("execution(* com..mapper.*.delete*(..))")
public Object monitorDeleteOperation(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
try {
return pjp.proceed();
} finally {
long cost = System.currentTimeMillis() - start;
Metrics.timer("db.delete.time").record(cost, TimeUnit.MILLISECONDS);
if (cost > 1000) {
log.warn("Delete operation slow: {}", pjp.getSignature());
}
}
}
这个切面可以帮助我们发现性能异常的删除操作,特别是当数据量增长后出现的慢删除问题。
6. 最佳实践与避坑指南
6.1 删除前备份策略
重要数据删除前建议自动备份:
java复制public int safeDeleteById(Long id) {
User user = userMapper.selectById(id);
if (user != null) {
backupService.backup(user);
return userMapper.deleteById(id);
}
return 0;
}
我曾经因为没有备份机制,不小心删除了生产环境的核心用户数据,最后花了3小时从binlog恢复。这个教训让我在所有项目中都加入了删除备份。
6.2 常见错误排查
- 删除不生效:检查是否开启了逻辑删除但实体类没有@TableLogic注解
- 批量删除部分失败:检查数据库引擎是否支持事务(如MyISAM不支持)
- 性能突然下降:检查是否缺少索引导致全表扫描
- 外键约束报错:先删除子表数据或配置级联删除
7. 扩展应用场景
7.1 定时清理任务
结合Spring Scheduler实现自动化清理:
java复制@Scheduled(cron = "0 0 3 * * ?")
public void autoCleanInactiveUsers() {
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.eq(User::getActive, false)
.lt(User::getLastLoginTime, LocalDateTime.now().minusYears(1));
int count = userMapper.delete(wrapper);
log.info("Cleaned {} inactive users", count);
}
7.2 审计日志集成
重要删除操作应该记录审计日志:
java复制public int deleteWithLog(Long id, String operator) {
User user = userMapper.selectById(id);
auditLogService.logDelete(user, operator);
return userMapper.deleteById(id);
}
这个简单的增强可以在出现问题时快速定位操作人和操作时间。
