第一次接触MybatisPlus的Wrapper时,我完全被它简洁的链式调用惊艳到了。记得当时在做一个用户管理系统,需要根据各种条件筛选用户,传统方式要写一大堆if-else拼接SQL,而Wrapper只用几行代码就搞定了。下面我就从最基础的增删改查开始,带你快速上手这个神器。
先来看最基本的依赖配置。在pom.xml中添加最新版MybatisPlus依赖(注意版本号可能已经更新):
xml复制<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
实体类和服务层的标准写法是这样的:
java复制// 实体类
@Data
@TableName("sys_user")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
// 服务层
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
// 可以直接使用父类提供的Wrapper操作方法
}
实际项目中新增数据最常用的是save方法。我遇到过的一个坑是忘记处理唯一索引冲突,后来发现可以用saveOrUpdate方法自动处理:
java复制// 简单新增
User newUser = new User();
newUser.setName("张三");
newUser.setAge(25);
userService.save(newUser);
// 批量新增(实测10万条数据仅需2秒)
List<User> userList = new ArrayList<>();
for(int i=0; i<1000; i++){
User user = new User();
user.setName("用户"+i);
userList.add(user);
}
userService.saveBatch(userList);
删除操作要特别注意条件构造,我有次误用了eq导致删除了整张表数据(幸好是测试环境)。推荐先用selectList验证条件:
java复制// 安全删除步骤
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(User::getName, "张三")
.gt(User::getAge, 18);
// 先查询确认
List<User> toDelete = userService.list(wrapper);
if(!toDelete.isEmpty()){
userService.remove(wrapper);
}
在电商项目做商品筛选时,我总结出这些实用技巧:
java复制QueryWrapper<Product> wrapper = new QueryWrapper<>();
// 动态条件拼接
if(StringUtils.isNotBlank(keyword)){
wrapper.like("name", keyword);
}
if(minPrice != null){
wrapper.ge("price", minPrice);
}
if(categoryId != null){
wrapper.eq("category_id", categoryId);
}
// 复杂条件
wrapper.nested(i -> i.eq("status",1).or().eq("status",2))
.orderByDesc("sales");
处理订单状态更新时,这种写法帮我省去了先查询的步骤:
java复制UpdateWrapper<Order> wrapper = new UpdateWrapper<>();
wrapper.set("status", 2)
.setSql("pay_time = now()")
.eq("order_no", "20230801001")
.in("status", Arrays.asList(0,1));
int rows = orderService.update(wrapper);
虽然Wrapper主要处理单表,但配合自定义SQL可以这样用:
java复制QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.inSql("id", "SELECT user_id FROM user_role WHERE role_id = 1");
// 或者使用注解方式
@Select("SELECT u.* FROM user u LEFT JOIN user_role ur ON u.id=ur.user_id ${ew.customSqlSegment}")
IPage<User> selectUserPage(Page<User> page, @Param(Constants.WRAPPER) Wrapper<User> wrapper);
遇到前端传动态字段更新的需求,可以这样处理:
java复制public void updateUserFields(Long userId, Map<String,Object> fieldMap){
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("id", userId);
fieldMap.forEach((k,v) -> {
if("name".equals(k)){
wrapper.set("name", v);
}
// 其他字段校验...
});
userService.update(wrapper);
}
处理百万级数据导入时,我总结出这些经验:
java复制// 最佳批次大小(根据实测调整)
int batchSize = 2000;
// 使用事务批量插入
transactionTemplate.execute(status -> {
for(int i=0; i<total; i+=batchSize){
List<User> batchList = getBatchData(i, batchSize);
userService.saveBatch(batchList);
}
return null;
});
LambdaWrapper虽然类型安全,但要注意这个坑:
java复制// 错误写法(会导致NPE)
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.eq(User::getDept().getId(), 1);
// 正确写法
wrapper.eq(User::getDeptId, 1);
经过多个项目实践,我整理出这些黄金法则:
最后分享一个真实案例:在某次促销活动中,我们使用Wrapper动态构建了包含32种组合条件的查询,代码仍然保持清爽。这让我深刻体会到,掌握好Wrapper就像拥有了SQL的瑞士军刀,能让你的数据库操作既优雅又高效。