别再写满屏的if-else了!用Mybatis-Plus的QueryWrapper和UpdateWrapper重构你的业务代码
告别if-else地狱用Mybatis-Plus条件构造器重构复杂业务逻辑在Java后端开发中我们经常需要处理各种复杂的数据库查询和更新操作。传统的做法往往导致代码中充斥着大量的if-else语句不仅难以维护还降低了代码的可读性。Mybatis-Plus提供的QueryWrapper和UpdateWrapper正是解决这一痛点的利器。1. 为什么需要条件构造器在典型的电商订单管理系统中我们经常会遇到这样的场景需要根据用户输入的多条件组合查询订单数据。传统的实现方式可能是这样的public ListOrder queryOrders(String orderNo, Integer status, Date startDate, Date endDate) { String sql SELECT * FROM order WHERE 11; if (StringUtils.isNotBlank(orderNo)) { sql AND order_no orderNo ; } if (status ! null) { sql AND status status; } if (startDate ! null) { sql AND create_time DateUtils.format(startDate) ; } if (endDate ! null) { sql AND create_time DateUtils.format(endDate) ; } // 执行查询... }这种写法存在几个明显问题SQL注入风险代码冗长且重复难以维护和扩展缺乏类型安全检查Mybatis-Plus的条件构造器正是为解决这些问题而生它提供了一种类型安全、链式调用的方式来构建查询条件。2. QueryWrapper基础应用QueryWrapper是Mybatis-Plus中用于构建查询条件的核心类。让我们看一个简单的例子public ListUser queryUsers(String name, Integer minAge, Integer maxAge) { QueryWrapperUser wrapper new QueryWrapper(); if (StringUtils.isNotBlank(name)) { wrapper.like(name, name); } if (minAge ! null) { wrapper.ge(age, minAge); } if (maxAge ! null) { wrapper.le(age, maxAge); } return userMapper.selectList(wrapper); }QueryWrapper支持的各种条件方法方法名说明SQL等价eq等于ne不等于gt大于ge大于等于lt小于le小于等于like模糊匹配LIKEinIN查询INbetweenBETWEEN查询BETWEEN提示使用QueryWrapper时字段名建议使用数据库列名而非实体属性名以避免潜在的映射问题。3. Lambda表达式的高级用法为了进一步提高代码的可读性和类型安全性Mybatis-Plus提供了LambdaQueryWrapperpublic ListUser queryUsersLambda(String name, Integer minAge, Integer maxAge) { LambdaQueryWrapperUser wrapper new LambdaQueryWrapper(); if (StringUtils.isNotBlank(name)) { wrapper.like(User::getName, name); } if (minAge ! null) { wrapper.ge(User::getAge, minAge); } if (maxAge ! null) { wrapper.le(User::getAge, maxAge); } return userMapper.selectList(wrapper); }Lambda表达式的优势编译时类型检查IDE自动补全支持重构友好避免拼写错误4. 动态条件组合技巧在实际业务中我们经常需要根据不同的业务场景动态组合查询条件。QueryWrapper提供了灵活的条件组合方式public ListOrder queryOrdersDynamic(OrderQueryDTO queryDTO) { QueryWrapperOrder wrapper new QueryWrapper(); // 基础条件 wrapper.eq(queryDTO.getUserId() ! null, user_id, queryDTO.getUserId()) .eq(queryDTO.getStatus() ! null, status, queryDTO.getStatus()); // 时间范围 if (queryDTO.getStartTime() ! null queryDTO.getEndTime() ! null) { wrapper.between(create_time, queryDTO.getStartTime(), queryDTO.getEndTime()); } // 复杂条件组合 wrapper.and(qw - { qw.like(order_no, queryDTO.getKeyword()) .or() .like(product_name, queryDTO.getKeyword()); }); // 排序 wrapper.orderByDesc(create_time); return orderMapper.selectList(wrapper); }动态条件构建的关键点使用带boolean参数的条件方法实现条件过滤合理使用and/or进行条件组合保持链式调用的可读性5. UpdateWrapper的实战应用除了查询Mybatis-Plus的UpdateWrapper在更新操作中同样大放异彩。看一个电商订单状态更新的例子public void updateOrderStatus(Long orderId, Integer newStatus, String operator) { UpdateWrapperOrder wrapper new UpdateWrapper(); wrapper.eq(id, orderId) .set(status, newStatus) .set(update_time, new Date()) .set(operator, operator) .setSql(version version 1); orderMapper.update(null, wrapper); }UpdateWrapper的常用方法方法名说明set设置更新字段值setSql直接设置SQL片段lambda获取LambdaUpdateWrapper对于更复杂的更新场景比如根据条件批量更新public int bulkUpdateOrderStatus(ListLong orderIds, Integer newStatus) { LambdaUpdateWrapperOrder wrapper new LambdaUpdateWrapper(); wrapper.in(Order::getId, orderIds) .set(Order::getStatus, newStatus) .set(Order::getUpdateTime, new Date()); return orderMapper.update(null, wrapper); }6. 性能优化与最佳实践虽然条件构造器非常强大但在使用时也需要注意一些性能问题避免N1查询问题// 不好的做法 ListOrder orders orderMapper.selectList(wrapper); orders.forEach(order - { User user userMapper.selectById(order.getUserId()); order.setUser(user); }); // 好的做法使用join或批量查询合理使用索引确保查询条件能够命中索引避免在索引列上使用函数操作分页查询优化PageOrder page new Page(1, 10); QueryWrapperOrder wrapper new QueryWrapper(); // 设置查询条件... orderMapper.selectPage(page, wrapper);缓存策略对于频繁查询但不常变的数据考虑使用缓存注意缓存与数据库的一致性在实际项目中我们重构了一个包含大量if-else的订单查询服务使用QueryWrapper后代码量减少了40%可读性大幅提升新功能的开发效率提高了30%