Mybatis学习笔记(四)
BaseMapper CRUD操作
简要描述:MybatisPlus的BaseMapper接口提供了丰富的CRUD操作方法,无需编写SQL即可完成常见的数据库操作,大大提高开发效率。
核心概念:
- BaseMapper接口:MybatisPlus提供的基础Mapper接口
- 泛型支持:通过泛型指定操作的实体类型
- 条件构造器:灵活的查询条件构建
- 批量操作:高效的批量数据处理
插入操作详解
简要描述:BaseMapper提供了多种插入方法,支持单条插入、批量插入、选择性插入等操作。
核心概念:
- insert:插入一条记录
- insertBatch:批量插入记录
- 选择性插入:只插入非空字段
- 主键回填:插入后自动回填主键值
基本插入方法:
public interface BaseMapper<T> extends Mapper<T> {/*** 插入一条记录* @param entity 实体对象* @return 影响行数*/int insert(T entity);
}
插入操作示例:
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 基本插入操作*/public void basicInsert() {// 1. 创建用户对象User user = new User();user.setName("张三");user.setEmail("zhangsan@example.com");user.setAge(25);// 2. 执行插入int result = userMapper.insert(user);System.out.println("插入结果:" + result); // 1System.out.println("用户ID:" + user.getId()); // 主键自动回填// 生成SQL:INSERT INTO t_user (id, name, email, age, create_time, update_time) // VALUES (?, ?, ?, ?, ?, ?)}/*** 批量插入操作(使用循环)*/public void batchInsertWithLoop() {List<User> userList = Arrays.asList(new User("李四", "lisi@example.com", 26),new User("王五", "wangwu@example.com", 27),new User("赵六", "zhaoliu@example.com", 28));for (User user : userList) {userMapper.insert(user);}}/*** 使用IService批量插入(推荐)*/public void batchInsertWithService() {List<User> userList = Arrays.asList(new User("张三", "zhangsan@example.com", 25),new User("李四", "lisi@example.com", 26),new User("王五", "wangwu@example.com", 27));// 使用IService的saveBatch方法boolean result = this.saveBatch(userList);System.out.println("批量插入结果:" + result);}
}// UserService继承IService
@Service
public class UserService extends ServiceImpl<UserMapper, User> implements IService<User> {/*** 批量插入(指定批次大小)*/public void batchInsertWithBatchSize() {List<User> userList = new ArrayList<>();for (int i = 1; i <= 1000; i++) {User user = new User();user.setName("用户" + i);user.setEmail("user" + i + "@example.com");user.setAge(20 + (i % 30));userList.add(user);}// 分批插入,每批100条boolean result = this.saveBatch(userList, 100);System.out.println("批量插入结果:" + result);}
}
插入时的字段填充:
// 实体类配置
@Data
@TableName("t_user")
public class User {@TableId(type = IdType.ASSIGN_ID)private Long id;private String name;private String email;private Integer age;// 自动填充字段@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;@TableField(fill = FieldFill.INSERT)private String createBy;@TableLogic@TableField(fill = FieldFill.INSERT)private Integer deleted;@Version@TableField(fill = FieldFill.INSERT)private Integer version;
}// 插入操作示例
@Test
public void testInsertWithAutoFill() {User user = new User();user.setName("测试用户");user.setEmail("test@example.com");user.setAge(25);// 插入时会自动填充createTime、updateTime、createBy、deleted、version等字段int result = userMapper.insert(user);System.out.println("插入结果:" + result);System.out.println("用户信息:" + user);// 输出:User(id=1234567890, name=测试用户, email=test@example.com, age=25, // createTime=2023-12-01T10:30:00, updateTime=2023-12-01T10:30:00, // createBy=system, deleted=0, version=1)
}
插入性能优化:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 高性能批量插入*/@Transactional(rollbackFor = Exception.class)public boolean highPerformanceBatchInsert(List<User> userList) {if (CollectionUtils.isEmpty(userList)) {return false;}// 1. 分批处理,避免内存溢出int batchSize = 1000;List<List<User>> batches = Lists.partition(userList, batchSize);for (List<User> batch : batches) {// 2. 使用批量插入boolean result = this.saveBatch(batch);if (!result) {throw new RuntimeException("批量插入失败");}}return true;}/*** 使用原生SQL批量插入(最高性能)*/public void batchInsertWithNativeSQL(List<User> userList) {if (CollectionUtils.isEmpty(userList)) {return;}// 构建批量插入SQLStringBuilder sql = new StringBuilder();sql.append("INSERT INTO t_user (name, email, age, create_time, update_time) VALUES ");List<Object> params = new ArrayList<>();for (int i = 0; i < userList.size(); i++) {if (i > 0) {sql.append(", ");}sql.append("(?, ?, ?, ?, ?)");User user = userList.get(i);params.add(user.getName());params.add(user.getEmail());params.add(user.getAge());params.add(LocalDateTime.now());params.add(LocalDateTime.now());}// 执行原生SQLSqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);try {sqlSession.update("batchInsertUsers", params.toArray());sqlSession.commit();} finally {sqlSession.close();}}
}
删除操作详解
简要描述:BaseMapper提供了多种删除方法,支持根据ID删除、根据条件删除、批量删除等操作。
核心概念:
- 物理删除:真正从数据库中删除记录
- 逻辑删除:通过标志位标记删除状态
- 条件删除:根据指定条件删除记录
- 批量删除:一次删除多条记录
删除方法列表:
public interface BaseMapper<T> extends Mapper<T> {/*** 根据 ID 删除*/int deleteById(Serializable id);/*** 根据实体(ID)删除*/int deleteById(T entity);/*** 根据 columnMap 条件删除记录*/int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根据 entity 条件删除记录*/int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 删除(根据ID 批量删除)*/int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
}
删除操作示例:
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 根据ID删除*/public void deleteById() {Long userId = 1L;int result = userMapper.deleteById(userId);System.out.println("删除结果:" + result);// 如果配置了逻辑删除,生成SQL:// UPDATE t_user SET deleted = 1 WHERE id = ? AND deleted = 0// 如果没有配置逻辑删除,生成SQL:// DELETE FROM t_user WHERE id = ?}/*** 根据实体删除*/public void deleteByEntity() {User user = new User();user.setId(1L);int result = userMapper.deleteById(user);System.out.println("删除结果:" + result);}/*** 根据Map条件删除*/public void deleteByMap() {Map<String, Object> columnMap = new HashMap<>();columnMap.put("name", "张三");columnMap.put("age", 25);int result = userMapper.deleteByMap(columnMap);System.out.println("删除结果:" + result);// 生成SQL:DELETE FROM t_user WHERE name = ? AND age = ?}/*** 根据条件构造器删除*/public void deleteByWrapper() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("name", "张三").lt("age", 30).isNotNull("email");int result = userMapper.delete(queryWrapper);System.out.println("删除结果:" + result);// 生成SQL:DELETE FROM t_user WHERE name = ? AND age < ? AND email IS NOT NULL}/*** 批量删除*/public void deleteBatchIds() {List<Long> idList = Arrays.asList(1L, 2L, 3L, 4L, 5L);int result = userMapper.deleteBatchIds(idList);System.out.println("批量删除结果:" + result);// 生成SQL:DELETE FROM t_user WHERE id IN (?, ?, ?, ?, ?)}
}
逻辑删除示例:
// 配置逻辑删除的实体类
@Data
@TableName("t_user")
public class User {@TableId(type = IdType.ASSIGN_ID)private Long id;private String name;private String email;private Integer age;// 逻辑删除字段@TableLogic@TableField("deleted")private Integer deleted; // 0-未删除,1-已删除@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;
}@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 逻辑删除测试*/public void testLogicDelete() {// 1. 插入数据User user = new User();user.setName("测试用户");user.setEmail("test@example.com");user.setAge(25);userMapper.insert(user); // deleted字段自动设置为0Long userId = user.getId();// 2. 查询数据(只查询未删除的)User queryUser = userMapper.selectById(userId);System.out.println("查询结果:" + queryUser); // 能查到数据// 3. 逻辑删除int deleteResult = userMapper.deleteById(userId);System.out.println("删除结果:" + deleteResult); // 1// 实际执行:UPDATE t_user SET deleted = 1 WHERE id = ? AND deleted = 0// 4. 再次查询(查询不到已删除的数据)User deletedUser = userMapper.selectById(userId);System.out.println("删除后查询:" + deletedUser); // null// 实际执行:SELECT * FROM t_user WHERE id = ? AND deleted = 0}/*** 查询包含已删除的数据*/public void selectWithDeleted() {// 使用原生SQL查询所有数据(包括已删除的)List<User> allUsers = userMapper.selectList(new QueryWrapper<User>().last("WHERE 1=1") // 绕过逻辑删除);// 或者使用@SqlParser(filter = true)注解的方法}
}
安全删除实践:
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 安全删除(带权限检查)*/public boolean safeDelete(Long userId, String currentUser) {// 1. 检查用户是否存在User user = userMapper.selectById(userId);if (user == null) {throw new BusinessException("用户不存在");}// 2. 权限检查(只能删除自己创建的用户)if (!currentUser.equals(user.getCreateBy())) {throw new BusinessException("无权限删除该用户");}// 3. 业务规则检查if ("admin".equals(user.getName())) {throw new BusinessException("管理员用户不能删除");}// 4. 执行删除int result = userMapper.deleteById(userId);return result > 0;}/*** 批量安全删除*/@Transactional(rollbackFor = Exception.class)public boolean batchSafeDelete(List<Long> userIds, String currentUser) {for (Long userId : userIds) {if (!safeDelete(userId, currentUser)) {throw new BusinessException("删除用户失败:" + userId);}}return true;}/*** 软删除恢复*/public boolean recoverDeleted(Long userId) {// 注意:这需要自定义SQL,因为MybatisPlus的逻辑删除不提供恢复功能UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();updateWrapper.eq("id", userId).eq("deleted", 1) // 只恢复已删除的.set("deleted", 0);int result = userMapper.update(null, updateWrapper);return result > 0;}
}
更新操作详解
简要描述:BaseMapper提供了多种更新方法,支持根据ID更新、根据条件更新、选择性更新等操作。
核心概念:
- 全量更新:更新实体的所有字段
- 选择性更新:只更新非空字段
- 条件更新:根据指定条件更新记录
- 乐观锁更新:基于版本号的并发控制
更新方法列表:
public interface BaseMapper<T> extends Mapper<T> {/*** 根据 ID 修改*/int updateById(@Param(Constants.ENTITY) T entity);/*** 根据 whereEntity 条件,更新记录*/int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
}
更新操作示例:
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 根据ID更新*/public void updateById() {// 1. 先查询获取完整对象User user = userMapper.selectById(1L);if (user != null) {// 2. 修改需要更新的字段user.setName("新名称");user.setEmail("newemail@example.com");// 3. 执行更新int result = userMapper.updateById(user);System.out.println("更新结果:" + result);// 生成SQL:UPDATE t_user SET name = ?, email = ?, update_time = ? // WHERE id = ? AND version = ?}}/*** 选择性更新(只更新非空字段)*/public void selectiveUpdate() {User user = new User();user.setId(1L);user.setName("新名称"); // 只设置需要更新的字段// email字段为null,不会被更新int result = userMapper.updateById(user);System.out.println("更新结果:" + result);// 生成SQL:UPDATE t_user SET name = ?, update_time = ? // WHERE id = ?}/*** 根据条件更新*/public void updateByWrapper() {// 1. 创建更新对象User user = new User();user.setEmail("batch@example.com");user.setAge(30);// 2. 创建更新条件UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();updateWrapper.eq("name", "张三").lt("age", 25);// 3. 执行更新int result = userMapper.update(user, updateWrapper);System.out.println("更新结果:" + result);// 生成SQL:UPDATE t_user SET email = ?, age = ?, update_time = ? // WHERE name = ? AND age < ?}/*** 使用UpdateWrapper直接设置字段值*/public void updateWithSetValue() {UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();updateWrapper.eq("name", "张三").set("email", "zhangsan_new@example.com").set("age", 26).setSql("update_time = now()"); // 使用SQL函数int result = userMapper.update(null, updateWrapper);System.out.println("更新结果:" + result);// 生成SQL:UPDATE t_user SET email = ?, age = ?, update_time = now() // WHERE name = ?}
}
乐观锁更新示例:
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 乐观锁更新*/public boolean updateWithOptimisticLock(Long userId, String newName) {// 1. 查询当前数据(获取版本号)User user = userMapper.selectById(userId);if (user == null) {return false;}// 2. 修改数据user.setName(newName);// 3. 执行更新(自动检查版本号)int result = userMapper.updateById(user);if (result > 0) {System.out.println("更新成功,新版本号:" + (user.getVersion() + 1));return true;} else {System.out.println("更新失败,数据已被其他用户修改");return false;}}/*** 带重试的乐观锁更新*/public boolean updateWithRetry(Long userId, String newName, int maxRetries) {for (int i = 0; i < maxRetries; i++) {try {if (updateWithOptimisticLock(userId, newName)) {return true;}// 短暂等待后重试Thread.sleep(100);} catch (InterruptedException e) {Thread.currentThread().interrupt();break;}}return false;}
}
批量更新操作:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 批量更新(使用IService)*/public boolean batchUpdate(List<User> userList) {// 使用IService的updateBatchById方法return this.updateBatchById(userList);}/*** 批量更新(指定批次大小)*/public boolean batchUpdateWithBatchSize(List<User> userList) {return this.updateBatchById(userList, 100); // 每批100条}/*** 条件批量更新*/public boolean batchUpdateByCondition() {// 将所有年龄小于18的用户状态设置为未成年UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();updateWrapper.lt("age", 18).set("status", 0).set("remark", "未成年用户");int result = this.getBaseMapper().update(null, updateWrapper);return result > 0;}/*** 高性能批量更新*/@Transactional(rollbackFor = Exception.class)public boolean highPerformanceBatchUpdate(List<User> userList) {if (CollectionUtils.isEmpty(userList)) {return false;}// 分批处理int batchSize = 1000;List<List<User>> batches = Lists.partition(userList, batchSize);for (List<User> batch : batches) {boolean result = this.updateBatchById(batch);if (!result) {throw new RuntimeException("批量更新失败");}}return true;}
}
字段自动填充更新:
// 实体类配置
@Data
@TableName("t_user")
public class User {@TableId(type = IdType.ASSIGN_ID)private Long id;private String name;private String email;private Integer age;@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;// 更新时自动填充@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;@TableField(fill = FieldFill.INSERT)private String createBy;// 更新时自动填充@TableField(fill = FieldFill.UPDATE)private String updateBy;@Version@TableField(fill = FieldFill.INSERT)private Integer version;
}// 更新操作会自动填充updateTime和updateBy字段
@Test
public void testUpdateWithAutoFill() {User user = new User();user.setId(1L);user.setName("更新后的名称");int result = userMapper.updateById(user);// updateTime和updateBy字段会被自动填充System.out.println("更新结果:" + result);
}
查询操作详解
简要描述:BaseMapper提供了丰富的查询方法,支持单条查询、批量查询、条件查询、分页查询等操作。
核心概念:
- 单条查询:根据ID或条件查询单条记录
- 批量查询:查询多条记录
- 条件查询:使用条件构造器进行复杂查询
- 分页查询:支持物理分页的查询
- 统计查询:查询记录数量
查询方法列表:
public interface BaseMapper<T> extends Mapper<T> {/*** 根据 ID 查询*/T selectById(Serializable id);/*** 根据 ID 批量查询*/List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);/*** 根据 columnMap 条件查询列表*/List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根据 entity 条件查询一条记录*/T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件查询总记录数*/Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 entity 条件查询全部记录*/List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件查询全部记录*/List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件查询全部记录(只返回第一个字段的值)*/List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 entity 条件查询全部记录(并翻页)*/<P extends IPage<T>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根据 Wrapper 条件查询全部记录(并翻页)*/<P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}
基本查询操作示例:
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 根据ID查询*/public void selectById() {Long userId = 1L;User user = userMapper.selectById(userId);System.out.println("查询结果:" + user);// 生成SQL:SELECT id, name, email, age, create_time, update_time // FROM t_user WHERE id = ? AND deleted = 0}/*** 批量ID查询*/public void selectBatchIds() {List<Long> idList = Arrays.asList(1L, 2L, 3L, 4L, 5L);List<User> userList = userMapper.selectBatchIds(idList);System.out.println("查询结果数量:" + userList.size());// 生成SQL:SELECT id, name, email, age, create_time, update_time // FROM t_user WHERE id IN (?, ?, ?, ?, ?) AND deleted = 0}/*** 根据Map条件查询*/public void selectByMap() {Map<String, Object> columnMap = new HashMap<>();columnMap.put("name", "张三");columnMap.put("age", 25);List<User> userList = userMapper.selectByMap(columnMap);System.out.println("查询结果:" + userList);// 生成SQL:SELECT * FROM t_user WHERE name = ? AND age = ? AND deleted = 0}/*** 查询单条记录*/public void selectOne() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("email", "zhangsan@example.com");User user = userMapper.selectOne(queryWrapper);System.out.println("查询结果:" + user);// 生成SQL:SELECT * FROM t_user WHERE email = ? AND deleted = 0 LIMIT 1}/*** 查询记录数*/public void selectCount() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.gt("age", 18).lt("age", 60);Integer count = userMapper.selectCount(queryWrapper);System.out.println("符合条件的记录数:" + count);// 生成SQL:SELECT COUNT(*) FROM t_user WHERE age > ? AND age < ? AND deleted = 0}/*** 查询所有记录*/public void selectList() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.orderByDesc("create_time").last("LIMIT 10"); // 限制查询数量List<User> userList = userMapper.selectList(queryWrapper);System.out.println("查询结果数量:" + userList.size());// 生成SQL:SELECT * FROM t_user WHERE deleted = 0 // ORDER BY create_time DESC LIMIT 10}
}
条件构造器查询示例:
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 复杂条件查询*/public void complexQuery() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper// 基本条件.eq("status", 1) // 状态等于1.ne("name", "admin") // 名称不等于admin.gt("age", 18) // 年龄大于18.lt("age", 60) // 年龄小于60.ge("create_time", "2023-01-01") // 创建时间大于等于.le("update_time", "2023-12-31") // 更新时间小于等于// 模糊查询.like("name", "张") // 名称包含"张".likeLeft("email", "@qq.com") // 邮箱以@qq.com结尾.likeRight("phone", "138") // 手机号以138开头// 空值判断.isNotNull("email") // 邮箱不为空.isNull("delete_time") // 删除时间为空// 范围查询.in("dept_id", Arrays.asList(1, 2, 3)) // 部门ID在指定范围内.notIn("role_id", Arrays.asList(99)) // 角色ID不在指定范围内.between("salary", 5000, 15000) // 薪资在5000-15000之间// 排序.orderByAsc("dept_id") // 按部门ID升序.orderByDesc("create_time"); // 按创建时间降序List<User> userList = userMapper.selectList(queryWrapper);System.out.println("查询结果数量:" + userList.size());}/*** OR条件查询*/public void orQuery() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("status", 1).and(wrapper -> wrapper.eq("dept_id", 1).or().eq("dept_id", 2)).or(wrapper -> wrapper.like("name", "管理员").like("name", "admin"));List<User> userList = userMapper.selectList(queryWrapper);// 生成SQL:SELECT * FROM t_user // WHERE status = ? AND (dept_id = ? OR dept_id = ?) // OR (name LIKE ? OR name LIKE ?) AND deleted = 0}/*** 嵌套查询*/public void nestedQuery() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.nested(wrapper -> wrapper.eq("status", 1).gt("age", 25)).or().nested(wrapper -> wrapper.eq("role_id", 1).isNotNull("manager_id"));List<User> userList = userMapper.selectList(queryWrapper);// 生成SQL:SELECT * FROM t_user // WHERE (status = ? AND age > ?) OR (role_id = ? AND manager_id IS NOT NULL) // AND deleted = 0}
}
分页查询示例:
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 基本分页查询*/public IPage<User> selectPage(int current, int size) {// 创建分页对象Page<User> page = new Page<>(current, size);// 创建查询条件QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.orderByDesc("create_time");// 执行分页查询IPage<User> userPage = userMapper.selectPage(page, queryWrapper);System.out.println("当前页:" + userPage.getCurrent());System.out.println("每页大小:" + userPage.getSize());System.out.println("总记录数:" + userPage.getTotal());System.out.println("总页数:" + userPage.getPages());System.out.println("当前页数据:" + userPage.getRecords());return userPage;}/*** 条件分页查询*/public IPage<User> selectPageWithCondition(int current, int size, String name, Integer minAge, Integer maxAge) {Page<User> page = new Page<>(current, size);QueryWrapper<User> queryWrapper = new QueryWrapper<>();// 动态条件if (StringUtils.isNotBlank(name)) {queryWrapper.like("name", name);}if (minAge != null) {queryWrapper.ge("age", minAge);}if (maxAge != null) {queryWrapper.le("age", maxAge);}queryWrapper.orderByDesc("create_time");return userMapper.selectPage(page, queryWrapper);}/*** 自定义分页查询(返回Map)*/public IPage<Map<String, Object>> selectMapsPage(int current, int size) {Page<Map<String, Object>> page = new Page<>(current, size);QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("id", "name", "email", "age") // 只查询指定字段.gt("age", 18).orderByDesc("create_time");return userMapper.selectMapsPage(page, queryWrapper);}/*** 不查询总记录数的分页(性能优化)*/public IPage<User> selectPageWithoutCount(int current, int size) {Page<User> page = new Page<>(current, size, false); // 不查询总数QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.orderByDesc("create_time");return userMapper.selectPage(page, queryWrapper);}
}
高级查询示例:
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 只查询指定字段*/public void selectSpecificColumns() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("id", "name", "email") // 只查询指定字段.eq("status", 1);List<User> userList = userMapper.selectList(queryWrapper);// 生成SQL:SELECT id, name, email FROM t_user WHERE status = ? AND deleted = 0}/*** 排除指定字段*/public void selectExcludeColumns() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select(User.class, info -> !info.getColumn().equals("password")) // 排除密码字段.eq("status", 1);List<User> userList = userMapper.selectList(queryWrapper);}/*** 函数查询*/public void selectWithFunction() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("id", "name", "DATE_FORMAT(create_time, '%Y-%m-%d') as create_date").apply("YEAR(create_time) = {0}", 2023); // 使用apply添加自定义SQLList<Map<String, Object>> result = userMapper.selectMaps(queryWrapper);// 生成SQL:SELECT id, name, DATE_FORMAT(create_time, '%Y-%m-%d') as create_date // FROM t_user WHERE YEAR(create_time) = ? AND deleted = 0}/*** 子查询*/public void selectWithSubQuery() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.inSql("dept_id", "SELECT id FROM t_dept WHERE status = 1") // 子查询.gt("age", 25);List<User> userList = userMapper.selectList(queryWrapper);// 生成SQL:SELECT * FROM t_user // WHERE dept_id IN (SELECT id FROM t_dept WHERE status = 1) // AND age > ? AND deleted = 0}/*** 分组查询*/public void selectWithGroupBy() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("dept_id", "COUNT(*) as user_count", "AVG(age) as avg_age").groupBy("dept_id").having("COUNT(*) > {0}", 5); // having条件List<Map<String, Object>> result = userMapper.selectMaps(queryWrapper);// 生成SQL:SELECT dept_id, COUNT(*) as user_count, AVG(age) as avg_age // FROM t_user WHERE deleted = 0 // GROUP BY dept_id HAVING COUNT(*) > ?}
}
查询性能优化:
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 流式查询(大数据量)*/public void streamQuery() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("status", 1);// 使用流式查询处理大量数据try (Stream<User> userStream = userMapper.selectList(queryWrapper).stream()) {userStream.filter(user -> user.getAge() > 25).map(User::getName).forEach(System.out::println);}}/*** 只查询第一个字段的值*/public void selectObjs() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("name") // 只查询name字段.eq("status", 1);List<Object> nameList = userMapper.selectObjs(queryWrapper);// 返回的是name字段的值列表nameList.forEach(name -> System.out.println("用户名:" + name));}/*** 缓存查询结果*/@Cacheable(value = "users", key = "#userId")public User selectByIdWithCache(Long userId) {return userMapper.selectById(userId);}/*** 批量查询优化*/public List<User> selectBatchOptimized(List<Long> userIds) {if (CollectionUtils.isEmpty(userIds)) {return Collections.emptyList();}// 分批查询,避免IN条件过长int batchSize = 1000;List<User> result = new ArrayList<>();List<List<Long>> batches = Lists.partition(userIds, batchSize);for (List<Long> batch : batches) {List<User> batchResult = userMapper.selectBatchIds(batch);result.addAll(batchResult);}return result;}
}
批量操作详解
简要描述:MybatisPlus提供了高效的批量操作方法,支持批量插入、批量更新、批量删除等操作,大大提高数据处理效率。
核心概念:
- IService接口:提供批量操作的服务层接口
- 批次处理:将大量数据分批处理,避免内存溢出
- 事务控制:批量操作的事务管理
- 性能优化:批量操作的性能优化策略
IService批量操作方法:
public interface IService<T> {/*** 批量插入*/boolean saveBatch(Collection<T> entityList);boolean saveBatch(Collection<T> entityList, int batchSize);/*** 批量插入或更新*/boolean saveOrUpdateBatch(Collection<T> entityList);boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);/*** 批量更新*/boolean updateBatchById(Collection<T> entityList);boolean updateBatchById(Collection<T> entityList, int batchSize);/*** 批量删除*/boolean removeByIds(Collection<? extends Serializable> idList);
}
批量操作示例:
@Service
public class UserService extends ServiceImpl<UserMapper, User> implements IService<User> {/*** 批量插入*/@Transactional(rollbackFor = Exception.class)public boolean batchInsert(List<User> userList) {if (CollectionUtils.isEmpty(userList)) {return false;}// 使用默认批次大小(1000)return this.saveBatch(userList);}/*** 自定义批次大小的批量插入*/@Transactional(rollbackFor = Exception.class)public boolean batchInsertWithCustomSize(List<User> userList, int batchSize) {return this.saveBatch(userList, batchSize);}/*** 批量插入或更新*/@Transactional(rollbackFor = Exception.class)public boolean batchSaveOrUpdate(List<User> userList) {// 根据主键判断是插入还是更新return this.saveOrUpdateBatch(userList);}/*** 批量更新*/@Transactional(rollbackFor = Exception.class)public boolean batchUpdate(List<User> userList) {return this.updateBatchById(userList);}/*** 批量删除*/@Transactional(rollbackFor = Exception.class)public boolean batchDelete(List<Long> userIds) {return this.removeByIds(userIds);}
}
高性能批量操作:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {@Autowiredprivate SqlSessionFactory sqlSessionFactory;/*** 高性能批量插入*/@Transactional(rollbackFor = Exception.class)public void highPerformanceBatchInsert(List<User> userList) {if (CollectionUtils.isEmpty(userList)) {return;}// 使用BATCH执行器SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);try {UserMapper mapper = sqlSession.getMapper(UserMapper.class);for (int i = 0; i < userList.size(); i++) {mapper.insert(userList.get(i));// 每1000条提交一次if (i % 1000 == 0 || i == userList.size() - 1) {sqlSession.flushStatements();}}sqlSession.commit();} catch (Exception e) {sqlSession.rollback();throw new RuntimeException("批量插入失败", e);} finally {sqlSession.close();}}/*** 使用原生SQL的批量插入*/@Transactional(rollbackFor = Exception.class)public void batchInsertWithNativeSQL(List<User> userList) {if (CollectionUtils.isEmpty(userList)) {return;}// 分批处理,每批1000条int batchSize = 1000;List<List<User>> batches = Lists.partition(userList, batchSize);for (List<User> batch : batches) {StringBuilder sql = new StringBuilder();sql.append("INSERT INTO t_user (name, email, age, create_time, update_time) VALUES ");List<Object> params = new ArrayList<>();for (int i = 0; i < batch.size(); i++) {if (i > 0) {sql.append(", ");}sql.append("(?, ?, ?, ?, ?)");User user = batch.get(i);params.add(user.getName());params.add(user.getEmail());params.add(user.getAge());params.add(LocalDateTime.now());params.add(LocalDateTime.now());}// 执行批量插入this.getBaseMapper().insertBatchSql(sql.toString(), params);}}/*** 并行批量处理*/@Transactional(rollbackFor = Exception.class)public void parallelBatchProcess(List<User> userList) {if (CollectionUtils.isEmpty(userList)) {return;}// 分批处理int batchSize = 1000;List<List<User>> batches = Lists.partition(userList, batchSize);// 并行处理各批次batches.parallelStream().forEach(batch -> {this.saveBatch(batch);});}
}
批量操作最佳实践:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 安全的批量操作*/@Transactional(rollbackFor = Exception.class)public BatchResult safeBatchOperation(List<User> userList, String operation) {BatchResult result = new BatchResult();if (CollectionUtils.isEmpty(userList)) {result.setSuccess(true);result.setMessage("没有数据需要处理");return result;}try {// 数据验证List<String> errors = validateUserList(userList);if (!errors.isEmpty()) {result.setSuccess(false);result.setErrors(errors);return result;}// 执行批量操作boolean success = false;switch (operation.toLowerCase()) {case "insert":success = this.saveBatch(userList);break;case "update":success = this.updateBatchById(userList);break;case "save_or_update":success = this.saveOrUpdateBatch(userList);break;default:throw new IllegalArgumentException("不支持的操作类型:" + operation);}result.setSuccess(success);result.setProcessedCount(userList.size());result.setMessage("批量操作完成");} catch (Exception e) {result.setSuccess(false);result.setMessage("批量操作失败:" + e.getMessage());throw new RuntimeException("批量操作失败", e);}return result;}/*** 数据验证*/private List<String> validateUserList(List<User> userList) {List<String> errors = new ArrayList<>();for (int i = 0; i < userList.size(); i++) {User user = userList.get(i);if (StringUtils.isBlank(user.getName())) {errors.add("第" + (i + 1) + "条记录:用户名不能为空");}if (StringUtils.isBlank(user.getEmail())) {errors.add("第" + (i + 1) + "条记录:邮箱不能为空");} else if (!isValidEmail(user.getEmail())) {errors.add("第" + (i + 1) + "条记录:邮箱格式不正确");}if (user.getAge() != null && (user.getAge() < 0 || user.getAge() > 150)) {errors.add("第" + (i + 1) + "条记录:年龄必须在0-150之间");}}return errors;}/*** 邮箱格式验证*/private boolean isValidEmail(String email) {String emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";return email.matches(emailRegex);}
}/*** 批量操作结果类*/
@Data
public class BatchResult {private boolean success;private String message;private int processedCount;private List<String> errors;public BatchResult() {this.errors = new ArrayList<>();}
}
自定义SQL与BaseMapper结合
简要描述:MybatisPlus允许在BaseMapper中自定义SQL语句,结合条件构造器使用,既保持了MybatisPlus的便利性,又提供了SQL的灵活性。
核心概念:
- @Select注解:用于自定义查询SQL
- @Insert注解:用于自定义插入SQL
- @Update注解:用于自定义更新SQL
- @Delete注解:用于自定义删除SQL
- XML映射:在XML文件中定义复杂SQL
- 条件构造器结合:自定义SQL与Wrapper结合使用
注解方式自定义SQL:
@Mapper
public interface UserMapper extends BaseMapper<User> {/*** 自定义查询SQL*/@Select("SELECT * FROM t_user WHERE age > #{age} AND status = 1")List<User> selectByAge(@Param("age") Integer age);/*** 复杂查询SQL*/@Select("SELECT u.*, d.dept_name " +"FROM t_user u " +"LEFT JOIN t_dept d ON u.dept_id = d.id " +"WHERE u.status = 1 " +"ORDER BY u.create_time DESC")List<Map<String, Object>> selectUserWithDept();/*** 统计查询*/@Select("SELECT dept_id, COUNT(*) as user_count, AVG(age) as avg_age " +"FROM t_user " +"WHERE status = 1 " +"GROUP BY dept_id " +"HAVING COUNT(*) > #{minCount}")List<Map<String, Object>> selectUserStatsByDept(@Param("minCount") Integer minCount);/*** 自定义插入SQL*/@Insert("INSERT INTO t_user (name, email, age, create_time, update_time) " +"VALUES (#{name}, #{email}, #{age}, NOW(), NOW())")@Options(useGeneratedKeys = true, keyProperty = "id")int insertUser(User user);/*** 批量插入SQL*/@Insert("<script>" +"INSERT INTO t_user (name, email, age, create_time, update_time) VALUES " +"<foreach collection='list' item='user' separator=','>" +"(#{user.name}, #{user.email}, #{user.age}, NOW(), NOW())" +"</foreach>" +"</script>")int insertBatchUsers(@Param("list") List<User> userList);/*** 自定义更新SQL*/@Update("UPDATE t_user SET name = #{name}, email = #{email}, " +"update_time = NOW() WHERE id = #{id} AND version = #{version}")int updateUserWithVersion(User user);/*** 条件更新SQL*/@Update("UPDATE t_user SET status = #{status}, update_time = NOW() " +"WHERE dept_id = #{deptId} AND age > #{minAge}")int updateUserStatusByCondition(@Param("status") Integer status, @Param("deptId") Long deptId, @Param("minAge") Integer minAge);/*** 自定义删除SQL*/@Delete("DELETE FROM t_user WHERE status = 0 AND update_time < #{beforeDate}")int deleteInactiveUsers(@Param("beforeDate") LocalDateTime beforeDate);/*** 软删除SQL*/@Update("UPDATE t_user SET deleted = 1, delete_time = NOW() " +"WHERE id IN (${ids}) AND deleted = 0")int softDeleteByIds(@Param("ids") String ids);
}
XML方式自定义SQL:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper"><!-- 复杂查询SQL --><select id="selectUserWithDeptAndRole" resultType="map">SELECT u.id,u.name,u.email,u.age,d.dept_name,r.role_name,u.create_timeFROM t_user uLEFT JOIN t_dept d ON u.dept_id = d.idLEFT JOIN t_user_role ur ON u.id = ur.user_idLEFT JOIN t_role r ON ur.role_id = r.idWHERE u.deleted = 0<if test="name != null and name != ''">AND u.name LIKE CONCAT('%', #{name}, '%')</if><if test="deptId != null">AND u.dept_id = #{deptId}</if><if test="minAge != null">AND u.age >= #{minAge}</if><if test="maxAge != null">AND u.age <= #{maxAge}</if>ORDER BY u.create_time DESC<if test="limit != null">LIMIT #{limit}</if></select><!-- 分页查询SQL --><select id="selectUserPage" resultType="com.example.entity.User">SELECT * FROM t_userWHERE deleted = 0<if test="ew != null"><if test="ew.sqlSegment != null and ew.sqlSegment != ''">AND ${ew.sqlSegment}</if></if></select><!-- 统计查询SQL --><select id="selectUserStats" resultType="map">SELECT COUNT(*) as total_count,COUNT(CASE WHEN status = 1 THEN 1 END) as active_count,COUNT(CASE WHEN status = 0 THEN 1 END) as inactive_count,AVG(age) as avg_age,MIN(age) as min_age,MAX(age) as max_age,DATE_FORMAT(MIN(create_time), '%Y-%m-%d') as earliest_date,DATE_FORMAT(MAX(create_time), '%Y-%m-%d') as latest_dateFROM t_userWHERE deleted = 0<if test="deptId != null">AND dept_id = #{deptId}</if></select><!-- 批量更新SQL --><update id="updateBatchByIds"><foreach collection="list" item="user" separator=";">UPDATE t_user<set><if test="user.name != null">name = #{user.name},</if><if test="user.email != null">email = #{user.email},</if><if test="user.age != null">age = #{user.age},</if>update_time = NOW()</set>WHERE id = #{user.id} AND deleted = 0</foreach></update><!-- 条件删除SQL --><delete id="deleteByCondition">DELETE FROM t_userWHERE deleted = 0<if test="status != null">AND status = #{status}</if><if test="beforeDate != null">AND create_time < #{beforeDate}</if><if test="deptIds != null and deptIds.size() > 0">AND dept_id IN<foreach collection="deptIds" item="deptId" open="(" close=")" separator=",">#{deptId}</foreach></if></delete><!-- 递归查询SQL --><select id="selectUserHierarchy" resultType="map">WITH RECURSIVE user_hierarchy AS (-- 查询根节点SELECT id, name, manager_id, 0 as levelFROM t_userWHERE manager_id IS NULL AND deleted = 0UNION ALL-- 递归查询子节点SELECT u.id, u.name, u.manager_id, uh.level + 1FROM t_user uINNER JOIN user_hierarchy uh ON u.manager_id = uh.idWHERE u.deleted = 0)SELECT * FROM user_hierarchyORDER BY level, id</select>
</mapper>
Mapper接口定义:
@Mapper
public interface UserMapper extends BaseMapper<User> {/*** 复杂查询*/List<Map<String, Object>> selectUserWithDeptAndRole(@Param("name") String name,@Param("deptId") Long deptId,@Param("minAge") Integer minAge,@Param("maxAge") Integer maxAge,@Param("limit") Integer limit);/*** 分页查询(结合条件构造器)*/IPage<User> selectUserPage(IPage<User> page, @Param(Constants.WRAPPER) Wrapper<User> wrapper);/*** 统计查询*/Map<String, Object> selectUserStats(@Param("deptId") Long deptId);/*** 批量更新*/int updateBatchByIds(@Param("list") List<User> userList);/*** 条件删除*/int deleteByCondition(@Param("status") Integer status,@Param("beforeDate") LocalDateTime beforeDate,@Param("deptIds") List<Long> deptIds);/*** 递归查询*/List<Map<String, Object>> selectUserHierarchy();
}
Service层使用示例:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 复杂查询示例*/public List<Map<String, Object>> getUserWithDeptAndRole(UserQueryDTO queryDTO) {return this.baseMapper.selectUserWithDeptAndRole(queryDTO.getName(),queryDTO.getDeptId(),queryDTO.getMinAge(),queryDTO.getMaxAge(),queryDTO.getLimit());}/*** 自定义分页查询*/public IPage<User> getUserPage(int current, int size, UserQueryDTO queryDTO) {Page<User> page = new Page<>(current, size);// 构建查询条件QueryWrapper<User> wrapper = new QueryWrapper<>();if (StringUtils.isNotBlank(queryDTO.getName())) {wrapper.like("name", queryDTO.getName());}if (queryDTO.getStatus() != null) {wrapper.eq("status", queryDTO.getStatus());}if (queryDTO.getMinAge() != null) {wrapper.ge("age", queryDTO.getMinAge());}if (queryDTO.getMaxAge() != null) {wrapper.le("age", queryDTO.getMaxAge());}return this.baseMapper.selectUserPage(page, wrapper);}/*** 获取用户统计信息*/public Map<String, Object> getUserStats(Long deptId) {return this.baseMapper.selectUserStats(deptId);}/*** 批量更新用户信息*/@Transactional(rollbackFor = Exception.class)public boolean batchUpdateUsers(List<User> userList) {if (CollectionUtils.isEmpty(userList)) {return false;}// 数据验证for (User user : userList) {if (user.getId() == null) {throw new IllegalArgumentException("用户ID不能为空");}}int updateCount = this.baseMapper.updateBatchByIds(userList);return updateCount > 0;}/*** 条件删除用户*/@Transactional(rollbackFor = Exception.class)public int deleteUsersByCondition(Integer status, LocalDateTime beforeDate, List<Long> deptIds) {return this.baseMapper.deleteByCondition(status, beforeDate, deptIds);}/*** 获取用户层级结构*/public List<Map<String, Object>> getUserHierarchy() {return this.baseMapper.selectUserHierarchy();}
}
条件构造器与自定义SQL结合:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 动态SQL查询*/public List<User> dynamicQuery(UserQueryDTO queryDTO) {// 使用条件构造器构建基础条件QueryWrapper<User> wrapper = new QueryWrapper<>();// 基础条件wrapper.eq("deleted", 0);// 动态条件if (StringUtils.isNotBlank(queryDTO.getName())) {wrapper.like("name", queryDTO.getName());}if (queryDTO.getDeptId() != null) {wrapper.eq("dept_id", queryDTO.getDeptId());}if (queryDTO.getStatus() != null) {wrapper.eq("status", queryDTO.getStatus());}if (queryDTO.getMinAge() != null && queryDTO.getMaxAge() != null) {wrapper.between("age", queryDTO.getMinAge(), queryDTO.getMaxAge());} else if (queryDTO.getMinAge() != null) {wrapper.ge("age", queryDTO.getMinAge());} else if (queryDTO.getMaxAge() != null) {wrapper.le("age", queryDTO.getMaxAge());}if (queryDTO.getCreateTimeStart() != null && queryDTO.getCreateTimeEnd() != null) {wrapper.between("create_time", queryDTO.getCreateTimeStart(), queryDTO.getCreateTimeEnd());}// 排序if (StringUtils.isNotBlank(queryDTO.getOrderBy())) {if ("asc".equalsIgnoreCase(queryDTO.getOrderDirection())) {wrapper.orderByAsc(queryDTO.getOrderBy());} else {wrapper.orderByDesc(queryDTO.getOrderBy());}} else {wrapper.orderByDesc("create_time");}return this.list(wrapper);}/*** 复杂条件查询*/public List<User> complexQuery(UserQueryDTO queryDTO) {QueryWrapper<User> wrapper = new QueryWrapper<>();// 基础条件wrapper.eq("deleted", 0);// 复杂条件组合wrapper.and(w -> {if (StringUtils.isNotBlank(queryDTO.getKeyword())) {w.like("name", queryDTO.getKeyword()).or().like("email", queryDTO.getKeyword()).or().like("phone", queryDTO.getKeyword());}return w;});// 部门条件if (CollectionUtils.isNotEmpty(queryDTO.getDeptIds())) {wrapper.in("dept_id", queryDTO.getDeptIds());}// 角色条件(子查询)if (CollectionUtils.isNotEmpty(queryDTO.getRoleIds())) {wrapper.inSql("id", "SELECT user_id FROM t_user_role WHERE role_id IN (" +queryDTO.getRoleIds().stream().map(String::valueOf).collect(Collectors.joining(",")) + ")");}// 状态条件if (queryDTO.getStatus() != null) {wrapper.eq("status", queryDTO.getStatus());}// 时间范围条件if (queryDTO.getCreateTimeStart() != null) {wrapper.ge("create_time", queryDTO.getCreateTimeStart());}if (queryDTO.getCreateTimeEnd() != null) {wrapper.le("create_time", queryDTO.getCreateTimeEnd());}return this.list(wrapper);}
}
性能优化建议:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 分页查询优化*/public IPage<User> optimizedPageQuery(int current, int size, UserQueryDTO queryDTO) {Page<User> page = new Page<>(current, size);// 如果不需要总数,可以设置为false提高性能if (queryDTO.isCountDisabled()) {page.setSearchCount(false);}QueryWrapper<User> wrapper = new QueryWrapper<>();// 只查询需要的字段wrapper.select("id", "name", "email", "age", "status", "create_time");// 添加查询条件buildQueryConditions(wrapper, queryDTO);return this.page(page, wrapper);}/*** 构建查询条件*/private void buildQueryConditions(QueryWrapper<User> wrapper, UserQueryDTO queryDTO) {wrapper.eq("deleted", 0);if (StringUtils.isNotBlank(queryDTO.getName())) {wrapper.like("name", queryDTO.getName());}if (queryDTO.getDeptId() != null) {wrapper.eq("dept_id", queryDTO.getDeptId());}if (queryDTO.getStatus() != null) {wrapper.eq("status", queryDTO.getStatus());}// 添加索引字段的查询条件if (queryDTO.getCreateTimeStart() != null) {wrapper.ge("create_time", queryDTO.getCreateTimeStart());}if (queryDTO.getCreateTimeEnd() != null) {wrapper.le("create_time", queryDTO.getCreateTimeEnd());}// 排序优化:使用索引字段排序wrapper.orderByDesc("create_time");}/*** 缓存查询结果*/@Cacheable(value = "userStats", key = "#deptId")public Map<String, Object> getCachedUserStats(Long deptId) {return this.baseMapper.selectUserStats(deptId);}/*** 异步查询*/@Asyncpublic CompletableFuture<List<User>> asyncQuery(UserQueryDTO queryDTO) {List<User> users = this.dynamicQuery(queryDTO);return CompletableFuture.completedFuture(users);}
}
条件构造器深入应用
QueryWrapper查询条件
简要描述:QueryWrapper是MybatisPlus中最常用的条件构造器,提供了丰富的方法来构建各种查询条件,支持链式调用,使用简单直观。
核心概念:
- 链式调用:支持方法链式调用,代码简洁
- 类型安全:编译时类型检查,避免字段名错误
- 动态条件:支持动态添加查询条件
- SQL注入防护:自动处理参数,防止SQL注入
- 多种条件:支持等值、范围、模糊、空值等各种条件
基本条件方法:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 等值条件*/public void equalConditions() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 等于wrapper.eq("name", "张三");// 生成SQL:name = '张三'// 不等于wrapper.ne("status", 0);// 生成SQL:status != 0List<User> users = this.list(wrapper);}/*** 范围条件*/public void rangeConditions() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 大于wrapper.gt("age", 18);// 生成SQL:age > 18// 大于等于wrapper.ge("salary", 5000);// 生成SQL:salary >= 5000// 小于wrapper.lt("age", 60);// 生成SQL:age < 60// 小于等于wrapper.le("salary", 20000);// 生成SQL:salary <= 20000// 区间条件wrapper.between("create_time", "2023-01-01", "2023-12-31");// 生成SQL:create_time BETWEEN '2023-01-01' AND '2023-12-31'// 不在区间wrapper.notBetween("age", 30, 40);// 生成SQL:age NOT BETWEEN 30 AND 40List<User> users = this.list(wrapper);}/*** 模糊查询条件*/public void likeConditions() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 包含wrapper.like("name", "张");// 生成SQL:name LIKE '%张%'// 不包含wrapper.notLike("name", "admin");// 生成SQL:name NOT LIKE '%admin%'// 左模糊wrapper.likeLeft("email", "@qq.com");// 生成SQL:email LIKE '%@qq.com'// 右模糊wrapper.likeRight("phone", "138");// 生成SQL:phone LIKE '138%'List<User> users = this.list(wrapper);}/*** 空值条件*/public void nullConditions() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 为空wrapper.isNull("delete_time");// 生成SQL:delete_time IS NULL// 不为空wrapper.isNotNull("email");// 生成SQL:email IS NOT NULLList<User> users = this.list(wrapper);}/*** 集合条件*/public void collectionConditions() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 在集合中List<Long> deptIds = Arrays.asList(1L, 2L, 3L);wrapper.in("dept_id", deptIds);// 生成SQL:dept_id IN (1, 2, 3)// 不在集合中List<Integer> statuses = Arrays.asList(0, -1);wrapper.notIn("status", statuses);// 生成SQL:status NOT IN (0, -1)List<User> users = this.list(wrapper);}
}
复杂条件组合:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** AND条件组合*/public void andConditions() {QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("status", 1) // 状态为1.gt("age", 18) // 年龄大于18.like("name", "张") // 姓名包含"张".isNotNull("email"); // 邮箱不为空// 生成SQL:status = 1 AND age > 18 AND name LIKE '%张%' AND email IS NOT NULLList<User> users = this.list(wrapper);}/*** OR条件组合*/public void orConditions() {QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("status", 1).or().eq("status", 2);// 生成SQL:status = 1 OR status = 2// 复杂OR条件wrapper.clear();wrapper.eq("dept_id", 1).or(w -> w.eq("role_id", 1).gt("age", 30));// 生成SQL:dept_id = 1 OR (role_id = 1 AND age > 30)List<User> users = this.list(wrapper);}/*** 嵌套条件*/public void nestedConditions() {QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("status", 1).and(w -> w.gt("age", 18).lt("age", 60)).or(w -> w.eq("role_id", 1).isNotNull("manager_id"));// 生成SQL:status = 1 AND (age > 18 AND age < 60) OR (role_id = 1 AND manager_id IS NOT NULL)List<User> users = this.list(wrapper);}/*** 条件分组*/public void groupConditions() {QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.nested(w -> w.eq("status", 1).gt("age", 25)).or().nested(w -> w.eq("role_id", 1).like("name", "管理员"));// 生成SQL:(status = 1 AND age > 25) OR (role_id = 1 AND name LIKE '%管理员%')List<User> users = this.list(wrapper);}
}
动态条件构建:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 动态条件查询*/public List<User> dynamicQuery(UserQueryDTO queryDTO) {QueryWrapper<User> wrapper = new QueryWrapper<>();// 基础条件wrapper.eq("deleted", 0);// 动态添加条件wrapper.eq(StringUtils.isNotBlank(queryDTO.getName()), "name", queryDTO.getName()).eq(queryDTO.getStatus() != null, "status", queryDTO.getStatus()).eq(queryDTO.getDeptId() != null, "dept_id", queryDTO.getDeptId()).ge(queryDTO.getMinAge() != null, "age", queryDTO.getMinAge()).le(queryDTO.getMaxAge() != null, "age", queryDTO.getMaxAge()).like(StringUtils.isNotBlank(queryDTO.getKeyword()), "name", queryDTO.getKeyword()).or(StringUtils.isNotBlank(queryDTO.getKeyword())).like(StringUtils.isNotBlank(queryDTO.getKeyword()), "email", queryDTO.getKeyword());// 时间范围条件if (queryDTO.getCreateTimeStart() != null && queryDTO.getCreateTimeEnd() != null) {wrapper.between("create_time", queryDTO.getCreateTimeStart(), queryDTO.getCreateTimeEnd());} else if (queryDTO.getCreateTimeStart() != null) {wrapper.ge("create_time", queryDTO.getCreateTimeStart());} else if (queryDTO.getCreateTimeEnd() != null) {wrapper.le("create_time", queryDTO.getCreateTimeEnd());}// 集合条件if (CollectionUtils.isNotEmpty(queryDTO.getDeptIds())) {wrapper.in("dept_id", queryDTO.getDeptIds());}// 排序if (StringUtils.isNotBlank(queryDTO.getOrderBy())) {if ("asc".equalsIgnoreCase(queryDTO.getOrderDirection())) {wrapper.orderByAsc(queryDTO.getOrderBy());} else {wrapper.orderByDesc(queryDTO.getOrderBy());}} else {wrapper.orderByDesc("create_time");}return this.list(wrapper);}/*** 条件构建器工厂方法*/public QueryWrapper<User> buildQueryWrapper(UserQueryDTO queryDTO) {QueryWrapper<User> wrapper = new QueryWrapper<>();// 基础条件wrapper.eq("deleted", 0);// 姓名条件if (StringUtils.isNotBlank(queryDTO.getName())) {if (queryDTO.isExactMatch()) {wrapper.eq("name", queryDTO.getName());} else {wrapper.like("name", queryDTO.getName());}}// 状态条件if (queryDTO.getStatus() != null) {wrapper.eq("status", queryDTO.getStatus());}// 部门条件if (queryDTO.getDeptId() != null) {wrapper.eq("dept_id", queryDTO.getDeptId());} else if (CollectionUtils.isNotEmpty(queryDTO.getDeptIds())) {wrapper.in("dept_id", queryDTO.getDeptIds());}// 年龄范围if (queryDTO.getMinAge() != null && queryDTO.getMaxAge() != null) {wrapper.between("age", queryDTO.getMinAge(), queryDTO.getMaxAge());} else {if (queryDTO.getMinAge() != null) {wrapper.ge("age", queryDTO.getMinAge());}if (queryDTO.getMaxAge() != null) {wrapper.le("age", queryDTO.getMaxAge());}}// 关键字搜索if (StringUtils.isNotBlank(queryDTO.getKeyword())) {wrapper.and(w -> w.like("name", queryDTO.getKeyword()).or().like("email", queryDTO.getKeyword()).or().like("phone", queryDTO.getKeyword()));}return wrapper;}
}
高级查询功能:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 子查询条件*/public void subQueryConditions() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 子查询INwrapper.inSql("dept_id", "SELECT id FROM t_dept WHERE status = 1");// 生成SQL:dept_id IN (SELECT id FROM t_dept WHERE status = 1)// 子查询NOT INwrapper.notInSql("id", "SELECT user_id FROM t_user_role WHERE role_id = 99");// 生成SQL:id NOT IN (SELECT user_id FROM t_user_role WHERE role_id = 99)// EXISTS子查询wrapper.exists("SELECT 1 FROM t_user_role ur WHERE ur.user_id = t_user.id AND ur.role_id = 1");// 生成SQL:EXISTS (SELECT 1 FROM t_user_role ur WHERE ur.user_id = t_user.id AND ur.role_id = 1)// NOT EXISTS子查询wrapper.notExists("SELECT 1 FROM t_user_role ur WHERE ur.user_id = t_user.id AND ur.role_id = 99");// 生成SQL:NOT EXISTS (SELECT 1 FROM t_user_role ur WHERE ur.user_id = t_user.id AND ur.role_id = 99)List<User> users = this.list(wrapper);}/*** 自定义SQL片段*/public void customSqlConditions() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 自定义SQL条件wrapper.apply("YEAR(create_time) = {0}", 2023);// 生成SQL:YEAR(create_time) = 2023// 复杂自定义条件wrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", "2023-12");// 生成SQL:DATE_FORMAT(create_time, '%Y-%m') = '2023-12'// 多参数自定义条件wrapper.apply("age BETWEEN {0} AND {1}", 25, 35);// 生成SQL:age BETWEEN 25 AND 35List<User> users = this.list(wrapper);}/*** 字段选择*/public void selectColumns() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 选择指定字段wrapper.select("id", "name", "email", "age");// 排除指定字段wrapper.select(User.class, info -> !"password".equals(info.getColumn()) && !"salt".equals(info.getColumn()));// 函数字段wrapper.select("id", "name", "YEAR(create_time) as create_year");List<User> users = this.list(wrapper);}/*** 分组和聚合*/public void groupByAndHaving() {QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.select("dept_id", "COUNT(*) as user_count", "AVG(age) as avg_age").groupBy("dept_id").having("COUNT(*) > {0}", 5).orderByDesc("user_count");// 生成SQL:SELECT dept_id, COUNT(*) as user_count, AVG(age) as avg_age // FROM t_user // GROUP BY dept_id // HAVING COUNT(*) > 5 // ORDER BY user_count DESCList<Map<String, Object>> result = this.listMaps(wrapper);}/*** 排序条件*/public void orderConditions() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 单字段排序wrapper.orderByAsc("age"); // 升序wrapper.orderByDesc("create_time"); // 降序// 多字段排序wrapper.orderByAsc("dept_id", "age");wrapper.orderByDesc("create_time", "update_time");// 混合排序wrapper.orderByAsc("dept_id").orderByDesc("create_time").orderByAsc("name");// 条件排序wrapper.orderBy(true, true, "age"); // condition, isAsc, columnList<User> users = this.list(wrapper);}
}
QueryWrapper最佳实践:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 可复用的条件构建*/public QueryWrapper<User> baseQueryWrapper() {QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("deleted", 0); // 基础条件:未删除return wrapper;}/*** 链式条件构建*/public List<User> chainQuery(UserQueryDTO queryDTO) {return this.list(this.baseQueryWrapper().eq(queryDTO.getStatus() != null, "status", queryDTO.getStatus()).like(StringUtils.isNotBlank(queryDTO.getName()), "name", queryDTO.getName()).in(CollectionUtils.isNotEmpty(queryDTO.getDeptIds()), "dept_id", queryDTO.getDeptIds()).between(queryDTO.getMinAge() != null && queryDTO.getMaxAge() != null, "age", queryDTO.getMinAge(), queryDTO.getMaxAge()).orderByDesc("create_time"));}/*** 条件构建器缓存*/private final Map<String, Function<UserQueryDTO, QueryWrapper<User>>> wrapperCache = new HashMap<>();{// 预定义常用查询条件wrapperCache.put("active", dto -> this.baseQueryWrapper().eq("status", 1));wrapperCache.put("byDept", dto -> this.baseQueryWrapper().eq("dept_id", dto.getDeptId()));wrapperCache.put("recent", dto -> this.baseQueryWrapper().ge("create_time", LocalDateTime.now().minusDays(30)));}public List<User> queryByType(String type, UserQueryDTO queryDTO) {Function<UserQueryDTO, QueryWrapper<User>> wrapperBuilder = wrapperCache.get(type);if (wrapperBuilder == null) {throw new IllegalArgumentException("不支持的查询类型:" + type);}return this.list(wrapperBuilder.apply(queryDTO));}/*** 性能优化的查询*/public List<User> optimizedQuery(UserQueryDTO queryDTO) {QueryWrapper<User> wrapper = new QueryWrapper<>();// 只查询必要字段wrapper.select("id", "name", "email", "status", "create_time");// 使用索引字段作为主要查询条件wrapper.eq("deleted", 0);// 优先使用等值查询if (queryDTO.getStatus() != null) {wrapper.eq("status", queryDTO.getStatus());}if (queryDTO.getDeptId() != null) {wrapper.eq("dept_id", queryDTO.getDeptId());}// 范围查询放在后面if (queryDTO.getCreateTimeStart() != null) {wrapper.ge("create_time", queryDTO.getCreateTimeStart());}// 模糊查询最后添加if (StringUtils.isNotBlank(queryDTO.getName())) {wrapper.like("name", queryDTO.getName());}// 使用索引字段排序wrapper.orderByDesc("create_time");return this.list(wrapper);}
}
UpdateWrapper更新条件
简要描述:UpdateWrapper是MybatisPlus专门用于构建更新条件的条件构造器,它继承自AbstractWrapper,不仅可以构建WHERE条件,还可以构建SET子句,实现复杂的更新操作。
核心概念:
- 条件更新:支持根据复杂条件进行更新操作
- 字段设置:可以直接设置要更新的字段值
- SQL函数:支持在SET子句中使用SQL函数
- 批量更新:支持批量更新操作
- 安全更新:防止全表更新,必须有WHERE条件
基本更新操作:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 基本字段更新*/public void basicUpdate() {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 设置要更新的字段wrapper.set("status", 1) // 设置状态为1.set("update_time", LocalDateTime.now()) // 设置更新时间.set("update_by", "admin"); // 设置更新人// 设置更新条件wrapper.eq("id", 1001L);// 执行更新this.update(wrapper);// 生成SQL:UPDATE t_user SET status = 1, update_time = '2023-12-01 10:00:00', update_by = 'admin' WHERE id = 1001}/*** 条件更新*/public void conditionalUpdate() {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 设置更新字段wrapper.set("status", 0).set("disable_time", LocalDateTime.now());// 设置更新条件wrapper.eq("dept_id", 10).lt("last_login_time", LocalDateTime.now().minusDays(30)).ne("status", 0);this.update(wrapper);// 生成SQL:UPDATE t_user SET status = 0, disable_time = '2023-12-01 10:00:00' // WHERE dept_id = 10 AND last_login_time < '2023-11-01 10:00:00' AND status != 0}/*** 使用SQL函数更新*/public void sqlFunctionUpdate() {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 使用SQL函数设置字段值wrapper.setSql("login_count = login_count + 1") // 登录次数加1.setSql("last_login_time = NOW()") // 设置最后登录时间为当前时间.setSql("version = version + 1"); // 版本号加1// 更新条件wrapper.eq("id", 1001L);this.update(wrapper);// 生成SQL:UPDATE t_user SET login_count = login_count + 1, last_login_time = NOW(), version = version + 1 WHERE id = 1001}/*** 批量更新不同字段*/public void batchUpdateDifferentFields() {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 根据不同条件更新不同字段wrapper.set("status", 1).set("audit_time", LocalDateTime.now()).set("audit_by", "admin");// 更新条件:待审核状态的用户wrapper.eq("status", 0).isNotNull("submit_time").ge("submit_time", LocalDateTime.now().minusDays(7));this.update(wrapper);}
}
复杂更新场景:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 条件性字段更新*/public void conditionalFieldUpdate(UserUpdateDTO updateDTO) {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 动态设置更新字段if (StringUtils.isNotBlank(updateDTO.getName())) {wrapper.set("name", updateDTO.getName());}if (updateDTO.getAge() != null) {wrapper.set("age", updateDTO.getAge());}if (StringUtils.isNotBlank(updateDTO.getEmail())) {wrapper.set("email", updateDTO.getEmail());}if (updateDTO.getStatus() != null) {wrapper.set("status", updateDTO.getStatus());}// 总是更新修改时间和修改人wrapper.set("update_time", LocalDateTime.now()).set("update_by", updateDTO.getUpdateBy());// 更新条件wrapper.eq("id", updateDTO.getId()).eq("version", updateDTO.getVersion()); // 乐观锁boolean success = this.update(wrapper);if (!success) {throw new RuntimeException("更新失败,数据可能已被其他用户修改");}}/*** 基于计算的字段更新*/public void calculatedFieldUpdate() {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 基于现有字段计算新值wrapper.setSql("total_score = (exam_score * 0.7 + homework_score * 0.3)").setSql("grade = CASE WHEN total_score >= 90 THEN 'A' WHEN total_score >= 80 THEN 'B' WHEN total_score >= 70 THEN 'C' ELSE 'D' END").set("calculate_time", LocalDateTime.now());// 更新条件:有考试成绩和作业成绩的学生wrapper.isNotNull("exam_score").isNotNull("homework_score").eq("status", 1);this.update(wrapper);}/*** 关联表更新*/public void relatedTableUpdate() {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 更新用户的部门信息wrapper.setSql("dept_name = (SELECT name FROM t_dept WHERE id = t_user.dept_id)").set("update_time", LocalDateTime.now());// 更新条件:部门名称为空的用户wrapper.isNull("dept_name").isNotNull("dept_id");this.update(wrapper);// 生成SQL:UPDATE t_user SET dept_name = (SELECT name FROM t_dept WHERE id = t_user.dept_id), update_time = '2023-12-01 10:00:00' // WHERE dept_name IS NULL AND dept_id IS NOT NULL}/*** 批量状态更新*/public void batchStatusUpdate(List<Long> userIds, Integer newStatus, String operator) {if (CollectionUtils.isEmpty(userIds)) {return;}UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 设置新状态wrapper.set("status", newStatus).set("status_update_time", LocalDateTime.now()).set("status_update_by", operator);// 更新条件wrapper.in("id", userIds).ne("status", newStatus); // 避免重复更新int updateCount = this.getBaseMapper().update(null, wrapper);log.info("批量更新用户状态,影响行数:{}", updateCount);}
}
高级更新功能:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 字段递增/递减更新*/public void incrementUpdate() {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 字段递增wrapper.setSql("login_count = login_count + 1") // 登录次数加1.setSql("total_points = total_points + {0}", 100) // 积分增加100.setSql("level = CASE WHEN total_points >= 1000 THEN 'VIP' ELSE 'NORMAL' END") // 根据积分设置等级.set("last_login_time", LocalDateTime.now());wrapper.eq("id", 1001L);this.update(wrapper);}/*** 条件性SQL更新*/public void conditionalSqlUpdate() {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 根据条件设置不同的SQLwrapper.setSql("salary = CASE " +"WHEN performance_score >= 90 THEN salary * 1.2 " +"WHEN performance_score >= 80 THEN salary * 1.1 " +"WHEN performance_score >= 70 THEN salary * 1.05 " +"ELSE salary END").setSql("bonus = CASE " +"WHEN performance_score >= 90 THEN 5000 " +"WHEN performance_score >= 80 THEN 3000 " +"WHEN performance_score >= 70 THEN 1000 " +"ELSE 0 END").set("salary_update_time", LocalDateTime.now());// 更新条件:有绩效评分的员工wrapper.isNotNull("performance_score").eq("status", 1).eq("salary_updated", 0);this.update(wrapper);}/*** 基于子查询的更新*/public void subQueryUpdate() {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 使用子查询更新字段wrapper.setSql("manager_name = (SELECT name FROM t_user m WHERE m.id = t_user.manager_id)").setSql("dept_name = (SELECT name FROM t_dept d WHERE d.id = t_user.dept_id)").set("info_update_time", LocalDateTime.now());// 更新条件:管理者姓名或部门名称为空wrapper.and(w -> w.isNull("manager_name").or().isNull("dept_name"));this.update(wrapper);}/*** 安全更新(防止全表更新)*/public void safeUpdate(UserUpdateDTO updateDTO) {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 设置更新字段wrapper.set("name", updateDTO.getName()).set("email", updateDTO.getEmail()).set("update_time", LocalDateTime.now());// 必须有WHERE条件if (updateDTO.getId() == null) {throw new IllegalArgumentException("更新操作必须指定ID");}wrapper.eq("id", updateDTO.getId());// 额外的安全检查if (updateDTO.getVersion() != null) {wrapper.eq("version", updateDTO.getVersion());}boolean success = this.update(wrapper);if (!success) {throw new RuntimeException("更新失败,请检查数据是否存在或已被修改");}}
}
UpdateWrapper与实体结合:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 实体+UpdateWrapper混合更新*/public void entityWithWrapper(User user, UserUpdateCondition condition) {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 设置更新条件wrapper.eq(condition.getDeptId() != null, "dept_id", condition.getDeptId()).eq(condition.getStatus() != null, "status", condition.getStatus()).ge(condition.getCreateTimeStart() != null, "create_time", condition.getCreateTimeStart()).le(condition.getCreateTimeEnd() != null, "create_time", condition.getCreateTimeEnd());// 使用实体进行更新(实体中的非null字段会被更新)this.update(user, wrapper);}/*** 选择性更新*/public void selectiveUpdate(UserUpdateDTO updateDTO) {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 只更新非空字段if (StringUtils.isNotBlank(updateDTO.getName())) {wrapper.set("name", updateDTO.getName());}if (StringUtils.isNotBlank(updateDTO.getEmail())) {wrapper.set("email", updateDTO.getEmail());}if (updateDTO.getAge() != null && updateDTO.getAge() > 0) {wrapper.set("age", updateDTO.getAge());}if (updateDTO.getStatus() != null) {wrapper.set("status", updateDTO.getStatus());}// 总是更新版本号和修改时间wrapper.setSql("version = version + 1").set("update_time", LocalDateTime.now()).set("update_by", updateDTO.getUpdateBy());// 更新条件wrapper.eq("id", updateDTO.getId());this.update(wrapper);}
}
UpdateWrapper最佳实践:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 事务性批量更新*/@Transactional(rollbackFor = Exception.class)public void transactionalBatchUpdate(List<UserUpdateDTO> updateList) {for (UserUpdateDTO updateDTO : updateList) {UpdateWrapper<User> wrapper = new UpdateWrapper<>();// 构建更新条件this.buildUpdateWrapper(wrapper, updateDTO);// 执行更新boolean success = this.update(wrapper);if (!success) {throw new RuntimeException("更新用户失败:" + updateDTO.getId());}}}/*** 构建更新条件的通用方法*/private void buildUpdateWrapper(UpdateWrapper<User> wrapper, UserUpdateDTO updateDTO) {// 设置更新字段if (StringUtils.isNotBlank(updateDTO.getName())) {wrapper.set("name", updateDTO.getName());}if (updateDTO.getStatus() != null) {wrapper.set("status", updateDTO.getStatus());}// 总是更新修改信息wrapper.set("update_time", LocalDateTime.now()).set("update_by", updateDTO.getUpdateBy()).setSql("version = version + 1");// 设置更新条件wrapper.eq("id", updateDTO.getId());// 乐观锁if (updateDTO.getVersion() != null) {wrapper.eq("version", updateDTO.getVersion());}}/*** 性能优化的批量更新*/public void optimizedBatchUpdate(List<UserUpdateDTO> updateList) {// 按更新类型分组Map<String, List<UserUpdateDTO>> groupedUpdates = updateList.stream().collect(Collectors.groupingBy(dto -> dto.getUpdateType()));// 分别处理不同类型的更新groupedUpdates.forEach((updateType, dtoList) -> {switch (updateType) {case "STATUS":this.batchUpdateStatus(dtoList);break;case "INFO":this.batchUpdateInfo(dtoList);break;default:this.defaultBatchUpdate(dtoList);}});}private void batchUpdateStatus(List<UserUpdateDTO> dtoList) {// 按状态值分组,减少SQL执行次数Map<Integer, List<Long>> statusGroups = dtoList.stream().collect(Collectors.groupingBy(UserUpdateDTO::getStatus,Collectors.mapping(UserUpdateDTO::getId, Collectors.toList())));statusGroups.forEach((status, ids) -> {UpdateWrapper<User> wrapper = new UpdateWrapper<>();wrapper.set("status", status).set("update_time", LocalDateTime.now()).in("id", ids);this.update(wrapper);});}private void batchUpdateInfo(List<UserUpdateDTO> dtoList) {// 逐个更新信息字段dtoList.forEach(dto -> {UpdateWrapper<User> wrapper = new UpdateWrapper<>();this.buildUpdateWrapper(wrapper, dto);this.update(wrapper);});}private void defaultBatchUpdate(List<UserUpdateDTO> dtoList) {// 默认批量更新逻辑dtoList.forEach(dto -> {UpdateWrapper<User> wrapper = new UpdateWrapper<>();this.buildUpdateWrapper(wrapper, dto);this.update(wrapper);});}
}
LambdaQueryWrapper类型安全查询
简要描述:LambdaQueryWrapper是MybatisPlus提供的类型安全的查询条件构造器,使用Lambda表达式来引用实体类的属性,避免了硬编码字段名,提供编译时类型检查,重构友好。
核心概念:
- 类型安全:使用Lambda表达式引用属性,编译时检查
- 重构友好:字段重命名时IDE可以自动重构
- 代码提示:IDE提供完整的代码提示和自动补全
- 避免魔法值:不需要硬编码字段名字符串
- 函数式编程:支持链式调用和函数式编程风格
基本使用方法:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 基本Lambda查询*/public void basicLambdaQuery() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// 使用Lambda表达式引用属性wrapper.eq(User::getName, "张三") // 等于.ne(User::getStatus, 0) // 不等于.gt(User::getAge, 18) // 大于.lt(User::getAge, 60) // 小于.like(User::getEmail, "@qq.com"); // 模糊查询List<User> users = this.list(wrapper);// 生成SQL:SELECT * FROM t_user WHERE name = '张三' AND status != 0 AND age > 18 AND age < 60 AND email LIKE '%@qq.com%'}/*** 范围查询*/public void rangeQuery() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.between(User::getAge, 25, 35) // 年龄在25-35之间.ge(User::getSalary, 5000) // 薪资大于等于5000.le(User::getCreateTime, LocalDateTime.now()) // 创建时间小于等于当前时间.in(User::getDeptId, Arrays.asList(1L, 2L, 3L)); // 部门ID在指定列表中List<User> users = this.list(wrapper);}/*** 空值查询*/public void nullQuery() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.isNull(User::getDeleteTime) // 删除时间为空.isNotNull(User::getEmail) // 邮箱不为空.eq(User::getDeleted, 0); // 未删除List<User> users = this.list(wrapper);}/*** 模糊查询*/public void likeQuery() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.like(User::getName, "张") // 姓名包含"张".likeLeft(User::getEmail, "@qq.com") // 邮箱以"@qq.com"结尾.likeRight(User::getPhone, "138") // 手机号以"138"开头.notLike(User::getName, "admin"); // 姓名不包含"admin"List<User> users = this.list(wrapper);}
}
复杂条件组合:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** AND条件组合*/public void andConditions() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getStatus, 1) // 状态为1.gt(User::getAge, 18) // 年龄大于18.like(User::getName, "张") // 姓名包含"张".isNotNull(User::getEmail); // 邮箱不为空// 默认使用AND连接List<User> users = this.list(wrapper);}/*** OR条件组合*/public void orConditions() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getStatus, 1).or().eq(User::getStatus, 2);// 生成SQL:status = 1 OR status = 2// 复杂OR条件wrapper.clear();wrapper.eq(User::getDeptId, 1).or(w -> w.eq(User::getRoleId, 1).gt(User::getAge, 30));// 生成SQL:dept_id = 1 OR (role_id = 1 AND age > 30)List<User> users = this.list(wrapper);}/*** 嵌套条件*/public void nestedConditions() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getStatus, 1).and(w -> w.gt(User::getAge, 18).lt(User::getAge, 60)).or(w -> w.eq(User::getRoleId, 1).isNotNull(User::getManagerId));// 生成SQL:status = 1 AND (age > 18 AND age < 60) OR (role_id = 1 AND manager_id IS NOT NULL)List<User> users = this.list(wrapper);}/*** 条件分组*/public void groupConditions() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.nested(w -> w.eq(User::getStatus, 1).gt(User::getAge, 25)).or().nested(w -> w.eq(User::getRoleId, 1).like(User::getName, "管理员"));// 生成SQL:(status = 1 AND age > 25) OR (role_id = 1 AND name LIKE '%管理员%')List<User> users = this.list(wrapper);}
}
动态条件构建:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 动态Lambda查询*/public List<User> dynamicLambdaQuery(UserQueryDTO queryDTO) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// 基础条件wrapper.eq(User::getDeleted, 0);// 动态添加条件wrapper.eq(StringUtils.isNotBlank(queryDTO.getName()), User::getName, queryDTO.getName()).eq(queryDTO.getStatus() != null, User::getStatus, queryDTO.getStatus()).eq(queryDTO.getDeptId() != null, User::getDeptId, queryDTO.getDeptId()).ge(queryDTO.getMinAge() != null, User::getAge, queryDTO.getMinAge()).le(queryDTO.getMaxAge() != null, User::getAge, queryDTO.getMaxAge()).like(StringUtils.isNotBlank(queryDTO.getKeyword()), User::getName, queryDTO.getKeyword()).or(StringUtils.isNotBlank(queryDTO.getKeyword())).like(StringUtils.isNotBlank(queryDTO.getKeyword()), User::getEmail, queryDTO.getKeyword());// 时间范围条件if (queryDTO.getCreateTimeStart() != null && queryDTO.getCreateTimeEnd() != null) {wrapper.between(User::getCreateTime, queryDTO.getCreateTimeStart(), queryDTO.getCreateTimeEnd());} else if (queryDTO.getCreateTimeStart() != null) {wrapper.ge(User::getCreateTime, queryDTO.getCreateTimeStart());} else if (queryDTO.getCreateTimeEnd() != null) {wrapper.le(User::getCreateTime, queryDTO.getCreateTimeEnd());}// 集合条件if (CollectionUtils.isNotEmpty(queryDTO.getDeptIds())) {wrapper.in(User::getDeptId, queryDTO.getDeptIds());}// 排序if (StringUtils.isNotBlank(queryDTO.getOrderBy())) {// 注意:Lambda方式的排序需要使用属性引用switch (queryDTO.getOrderBy()) {case "name":wrapper.orderBy(true, "asc".equalsIgnoreCase(queryDTO.getOrderDirection()), User::getName);break;case "age":wrapper.orderBy(true, "asc".equalsIgnoreCase(queryDTO.getOrderDirection()), User::getAge);break;case "createTime":wrapper.orderBy(true, "asc".equalsIgnoreCase(queryDTO.getOrderDirection()), User::getCreateTime);break;default:wrapper.orderByDesc(User::getCreateTime);}} else {wrapper.orderByDesc(User::getCreateTime);}return this.list(wrapper);}/*** 条件构建器工厂方法*/public LambdaQueryWrapper<User> buildLambdaWrapper(UserQueryDTO queryDTO) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// 基础条件wrapper.eq(User::getDeleted, 0);// 姓名条件if (StringUtils.isNotBlank(queryDTO.getName())) {if (queryDTO.isExactMatch()) {wrapper.eq(User::getName, queryDTO.getName());} else {wrapper.like(User::getName, queryDTO.getName());}}// 状态条件if (queryDTO.getStatus() != null) {wrapper.eq(User::getStatus, queryDTO.getStatus());}// 部门条件if (queryDTO.getDeptId() != null) {wrapper.eq(User::getDeptId, queryDTO.getDeptId());} else if (CollectionUtils.isNotEmpty(queryDTO.getDeptIds())) {wrapper.in(User::getDeptId, queryDTO.getDeptIds());}// 年龄范围if (queryDTO.getMinAge() != null && queryDTO.getMaxAge() != null) {wrapper.between(User::getAge, queryDTO.getMinAge(), queryDTO.getMaxAge());} else {if (queryDTO.getMinAge() != null) {wrapper.ge(User::getAge, queryDTO.getMinAge());}if (queryDTO.getMaxAge() != null) {wrapper.le(User::getAge, queryDTO.getMaxAge());}}// 关键字搜索if (StringUtils.isNotBlank(queryDTO.getKeyword())) {wrapper.and(w -> w.like(User::getName, queryDTO.getKeyword()).or().like(User::getEmail, queryDTO.getKeyword()).or().like(User::getPhone, queryDTO.getKeyword()));}return wrapper;}
}
高级Lambda查询:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 字段选择*/public void selectColumns() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// 选择指定字段wrapper.select(User::getId, User::getName, User::getEmail, User::getAge);// 排除指定字段wrapper.select(User.class, info -> !"password".equals(info.getColumn()) && !"salt".equals(info.getColumn()));List<User> users = this.list(wrapper);}/*** 分组和聚合*/public void groupByAndHaving() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.select("dept_id", "COUNT(*) as user_count", "AVG(age) as avg_age").groupBy(User::getDeptId).having("COUNT(*) > {0}", 5).orderByDesc("user_count");List<Map<String, Object>> result = this.listMaps(wrapper);}/*** 排序条件*/public void orderConditions() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// 单字段排序wrapper.orderByAsc(User::getAge); // 升序wrapper.orderByDesc(User::getCreateTime); // 降序// 多字段排序wrapper.orderByAsc(User::getDeptId, User::getAge);wrapper.orderByDesc(User::getCreateTime, User::getUpdateTime);// 混合排序wrapper.orderByAsc(User::getDeptId).orderByDesc(User::getCreateTime).orderByAsc(User::getName);// 条件排序wrapper.orderBy(true, true, User::getAge); // condition, isAsc, columnList<User> users = this.list(wrapper);}/*** 子查询条件*/public void subQueryConditions() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// 子查询INwrapper.inSql(User::getDeptId, "SELECT id FROM t_dept WHERE status = 1");// 子查询NOT INwrapper.notInSql(User::getId, "SELECT user_id FROM t_user_role WHERE role_id = 99");// EXISTS子查询wrapper.exists("SELECT 1 FROM t_user_role ur WHERE ur.user_id = t_user.id AND ur.role_id = 1");// NOT EXISTS子查询wrapper.notExists("SELECT 1 FROM t_user_role ur WHERE ur.user_id = t_user.id AND ur.role_id = 99");List<User> users = this.list(wrapper);}
}
Lambda查询最佳实践:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 可复用的Lambda条件构建*/public LambdaQueryWrapper<User> baseLambdaWrapper() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getDeleted, 0); // 基础条件:未删除return wrapper;}/*** 链式Lambda条件构建*/public List<User> chainLambdaQuery(UserQueryDTO queryDTO) {return this.list(this.baseLambdaWrapper().eq(queryDTO.getStatus() != null, User::getStatus, queryDTO.getStatus()).like(StringUtils.isNotBlank(queryDTO.getName()), User::getName, queryDTO.getName()).in(CollectionUtils.isNotEmpty(queryDTO.getDeptIds()), User::getDeptId, queryDTO.getDeptIds()).between(queryDTO.getMinAge() != null && queryDTO.getMaxAge() != null, User::getAge, queryDTO.getMinAge(), queryDTO.getMaxAge()).orderByDesc(User::getCreateTime));}/*** Lambda条件构建器缓存*/private final Map<String, Function<UserQueryDTO, LambdaQueryWrapper<User>>> lambdaWrapperCache = new HashMap<>();{// 预定义常用Lambda查询条件lambdaWrapperCache.put("active", dto -> this.baseLambdaWrapper().eq(User::getStatus, 1));lambdaWrapperCache.put("byDept", dto -> this.baseLambdaWrapper().eq(User::getDeptId, dto.getDeptId()));lambdaWrapperCache.put("recent", dto -> this.baseLambdaWrapper().ge(User::getCreateTime, LocalDateTime.now().minusDays(30)));}public List<User> queryByLambdaType(String type, UserQueryDTO queryDTO) {Function<UserQueryDTO, LambdaQueryWrapper<User>> wrapperBuilder = lambdaWrapperCache.get(type);if (wrapperBuilder == null) {throw new IllegalArgumentException("不支持的查询类型:" + type);}return this.list(wrapperBuilder.apply(queryDTO));}/*** 性能优化的Lambda查询*/public List<User> optimizedLambdaQuery(UserQueryDTO queryDTO) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// 只查询必要字段wrapper.select(User::getId, User::getName, User::getEmail, User::getStatus, User::getCreateTime);// 使用索引字段作为主要查询条件wrapper.eq(User::getDeleted, 0);// 优先使用等值查询if (queryDTO.getStatus() != null) {wrapper.eq(User::getStatus, queryDTO.getStatus());}if (queryDTO.getDeptId() != null) {wrapper.eq(User::getDeptId, queryDTO.getDeptId());}// 范围查询放在后面if (queryDTO.getCreateTimeStart() != null) {wrapper.ge(User::getCreateTime, queryDTO.getCreateTimeStart());}// 模糊查询最后添加if (StringUtils.isNotBlank(queryDTO.getName())) {wrapper.like(User::getName, queryDTO.getName());}// 使用索引字段排序wrapper.orderByDesc(User::getCreateTime);return this.list(wrapper);}/*** Lambda表达式与字符串混合使用*/public List<User> mixedQuery(UserQueryDTO queryDTO) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// Lambda表达式用于常规字段wrapper.eq(User::getStatus, 1).gt(User::getAge, 18);// 字符串用于复杂SQL或动态字段if (StringUtils.isNotBlank(queryDTO.getCustomField())) {wrapper.apply("JSON_EXTRACT(extra_info, '$." + queryDTO.getCustomField() + "') IS NOT NULL");}// 自定义SQL条件wrapper.apply("YEAR(create_time) = {0}", 2023);return this.list(wrapper);}/*** 类型安全的分页查询*/public IPage<User> lambdaPageQuery(UserQueryDTO queryDTO, long current, long size) {LambdaQueryWrapper<User> wrapper = this.buildLambdaWrapper(queryDTO);Page<User> page = new Page<>(current, size);return this.page(page, wrapper);}
}
Lambda查询的优势:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 对比普通QueryWrapper和LambdaQueryWrapper*/public void comparisonExample() {// 普通QueryWrapper - 使用字符串字段名QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("name", "张三") // 字段名硬编码,容易出错.gt("age", 18).like("email", "@qq.com");// LambdaQueryWrapper - 使用Lambda表达式LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();lambdaWrapper.eq(User::getName, "张三") // 类型安全,IDE可以检查.gt(User::getAge, 18) // 重构友好.like(User::getEmail, "@qq.com"); // 代码提示完整// 当User实体的字段名发生变化时:// - QueryWrapper需要手动修改所有字符串字段名// - LambdaQueryWrapper会自动跟随重构,编译时发现错误}/*** Lambda查询的类型安全示例*/public void typeSafetyExample() {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// 编译时类型检查wrapper.eq(User::getAge, 25); // 正确:age是Integer类型// wrapper.eq(User::getAge, "25"); // 编译错误:类型不匹配wrapper.like(User::getName, "张"); // 正确:name是String类型// wrapper.like(User::getAge, "张"); // 编译错误:age不是String类型wrapper.in(User::getDeptId, Arrays.asList(1L, 2L, 3L)); // 正确:deptId是Long类型// wrapper.in(User::getDeptId, Arrays.asList("1", "2")); // 编译错误:类型不匹配}
}
LambdaUpdateWrapper类型安全更新
简要描述:LambdaUpdateWrapper是MybatisPlus提供的类型安全的更新条件构造器,使用Lambda表达式来引用实体类的属性,避免了硬编码字段名,提供编译时类型检查,支持复杂的更新条件和字段设置。
核心概念:
- 类型安全更新:使用Lambda表达式引用属性,编译时检查
- 条件更新:支持复杂的WHERE条件
- 字段设置:支持SET子句的字段更新
- SQL函数支持:支持数据库函数和表达式
- 批量更新:支持批量条件更新操作
基本使用方法:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 基本Lambda更新*/public void basicLambdaUpdate() {LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();// 设置更新字段wrapper.set(User::getStatus, 1) // 设置状态为1.set(User::getUpdateTime, LocalDateTime.now()) // 设置更新时间.set(User::getUpdatedBy, "admin"); // 设置更新人// 设置更新条件wrapper.eq(User::getId, 1L) // 根据ID更新.eq(User::getDeleted, 0); // 未删除的记录this.update(wrapper);// 生成SQL:UPDATE t_user SET status = 1, update_time = '2023-12-01 10:00:00', updated_by = 'admin' // WHERE id = 1 AND deleted = 0}/*** 条件性字段更新*/public void conditionalUpdate() {LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();// 根据不同条件设置不同字段wrapper.set(User::getStatus, 1).set(User::getUpdateTime, LocalDateTime.now()).setSql("login_count = login_count + 1") // 使用SQL表达式.eq(User::getEmail, "user@example.com").gt(User::getAge, 18);this.update(wrapper);}/*** 批量状态更新*/public void batchStatusUpdate() {LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();wrapper.set(User::getStatus, 0) // 设置为禁用状态.set(User::getUpdateTime, LocalDateTime.now()).in(User::getId, Arrays.asList(1L, 2L, 3L, 4L)) // 批量ID.eq(User::getDeleted, 0); // 未删除this.update(wrapper);}/*** 基于计算的字段更新*/public void calculatedUpdate() {LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();// 使用SQL函数和表达式wrapper.setSql("salary = salary * 1.1") // 薪资增长10%.setSql("bonus = salary * 0.2") // 奖金为薪资的20%.setSql("last_login = NOW()") // 设置最后登录时间.eq(User::getDeptId, 1L).eq(User::getStatus, 1);this.update(wrapper);}
}
复杂更新场景:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 多条件复杂更新*/public void complexUpdate() {LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();wrapper.set(User::getStatus, 1).set(User::getUpdateTime, LocalDateTime.now()).set(User::getUpdatedBy, "system").eq(User::getDeptId, 1L).and(w -> w.gt(User::getAge, 25).lt(User::getAge, 60)).or(w -> w.eq(User::getRoleId, 1L).isNotNull(User::getManagerId));// 生成SQL:UPDATE t_user SET status = 1, update_time = NOW(), updated_by = 'system' // WHERE dept_id = 1 AND (age > 25 AND age < 60) OR (role_id = 1 AND manager_id IS NOT NULL)this.update(wrapper);}/*** 关联表更新(子查询)*/public void subQueryUpdate() {LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();wrapper.set(User::getDeptName, "研发部").set(User::getUpdateTime, LocalDateTime.now()).inSql(User::getDeptId, "SELECT id FROM t_dept WHERE name = '技术部'");this.update(wrapper);}/*** 动态更新字段*/public boolean dynamicUpdate(Long userId, UserUpdateDTO updateDTO) {LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();// 基础条件wrapper.eq(User::getId, userId).eq(User::getDeleted, 0);// 动态设置更新字段boolean hasUpdate = false;if (StringUtils.isNotBlank(updateDTO.getName())) {wrapper.set(User::getName, updateDTO.getName());hasUpdate = true;}if (updateDTO.getAge() != null) {wrapper.set(User::getAge, updateDTO.getAge());hasUpdate = true;}if (StringUtils.isNotBlank(updateDTO.getEmail())) {wrapper.set(User::getEmail, updateDTO.getEmail());hasUpdate = true;}if (updateDTO.getStatus() != null) {wrapper.set(User::getStatus, updateDTO.getStatus());hasUpdate = true;}if (updateDTO.getDeptId() != null) {wrapper.set(User::getDeptId, updateDTO.getDeptId());hasUpdate = true;}// 总是更新修改时间if (hasUpdate) {wrapper.set(User::getUpdateTime, LocalDateTime.now());wrapper.set(User::getUpdatedBy, updateDTO.getUpdatedBy());return this.update(wrapper);}return false;}/*** 批量条件更新*/public void batchConditionalUpdate() {// 更新所有技术部门员工的薪资LambdaUpdateWrapper<User> techWrapper = new LambdaUpdateWrapper<>();techWrapper.setSql("salary = salary * 1.15") // 技术部门涨薪15%.set(User::getUpdateTime, LocalDateTime.now()).eq(User::getDeptId, 1L).eq(User::getStatus, 1);this.update(techWrapper);// 更新所有销售部门员工的提成LambdaUpdateWrapper<User> salesWrapper = new LambdaUpdateWrapper<>();salesWrapper.setSql("commission_rate = commission_rate + 0.02") // 提成率增加2%.set(User::getUpdateTime, LocalDateTime.now()).eq(User::getDeptId, 2L).eq(User::getStatus, 1);this.update(salesWrapper);// 更新所有管理层的管理津贴LambdaUpdateWrapper<User> managerWrapper = new LambdaUpdateWrapper<>();managerWrapper.setSql("management_allowance = salary * 0.1") // 管理津贴为薪资的10%.set(User::getUpdateTime, LocalDateTime.now()).eq(User::getRoleId, 1L).eq(User::getStatus, 1);this.update(managerWrapper);}
}
高级更新功能:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 字段递增/递减更新*/public void incrementUpdate() {LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();// 登录次数+1wrapper.setSql("login_count = login_count + 1").set(User::getLastLoginTime, LocalDateTime.now()).eq(User::getId, 1L);this.update(wrapper);// 积分增加LambdaUpdateWrapper<User> pointsWrapper = new LambdaUpdateWrapper<>();pointsWrapper.setSql("points = points + {0}", 100) // 增加100积分.set(User::getUpdateTime, LocalDateTime.now()).eq(User::getId, 1L);this.update(pointsWrapper);// 余额扣减LambdaUpdateWrapper<User> balanceWrapper = new LambdaUpdateWrapper<>();balanceWrapper.setSql("balance = balance - {0}", 50.0) // 扣减50元.set(User::getUpdateTime, LocalDateTime.now()).eq(User::getId, 1L).ge(User::getBalance, 50.0); // 余额充足才扣减this.update(balanceWrapper);}/*** 条件性SQL更新*/public void conditionalSqlUpdate() {LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();// 使用CASE WHEN进行条件更新wrapper.setSql("status = CASE " +"WHEN age >= 60 THEN 2 " + // 退休状态"WHEN age >= 18 THEN 1 " + // 正常状态"ELSE 0 END") // 未成年状态.set(User::getUpdateTime, LocalDateTime.now()).eq(User::getDeleted, 0);this.update(wrapper);// 根据部门设置不同的薪资系数LambdaUpdateWrapper<User> salaryWrapper = new LambdaUpdateWrapper<>();salaryWrapper.setSql("salary = base_salary * CASE " +"WHEN dept_id = 1 THEN 1.2 " + // 技术部门系数1.2"WHEN dept_id = 2 THEN 1.1 " + // 销售部门系数1.1"ELSE 1.0 END") // 其他部门系数1.0.set(User::getUpdateTime, LocalDateTime.now()).eq(User::getStatus, 1);this.update(salaryWrapper);}/*** 基于子查询的更新*/public void subQueryBasedUpdate() {LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();// 根据部门平均薪资更新员工等级wrapper.setSql("level = CASE " +"WHEN salary > (SELECT AVG(salary) FROM t_user WHERE dept_id = t_user.dept_id) THEN 'HIGH' " +"WHEN salary > (SELECT AVG(salary) FROM t_user WHERE dept_id = t_user.dept_id) * 0.8 THEN 'MEDIUM' " +"ELSE 'LOW' END").set(User::getUpdateTime, LocalDateTime.now()).eq(User::getStatus, 1);this.update(wrapper);// 更新部门人数统计LambdaUpdateWrapper<User> deptCountWrapper = new LambdaUpdateWrapper<>();deptCountWrapper.setSql("dept_count = (SELECT COUNT(*) FROM t_user WHERE dept_id = t_user.dept_id AND deleted = 0)").set(User::getUpdateTime, LocalDateTime.now()).eq(User::getDeleted, 0);this.update(deptCountWrapper);}/*** 安全更新(防止全表更新)*/public boolean safeUpdate(UserUpdateDTO updateDTO) {// 检查更新条件,防止全表更新if (updateDTO.getId() == null && updateDTO.getEmail() == null && CollectionUtils.isEmpty(updateDTO.getIds())) {throw new IllegalArgumentException("更新操作必须指定具体的条件,不允许全表更新");}LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();// 设置更新字段if (StringUtils.isNotBlank(updateDTO.getName())) {wrapper.set(User::getName, updateDTO.getName());}if (updateDTO.getStatus() != null) {wrapper.set(User::getStatus, updateDTO.getStatus());}wrapper.set(User::getUpdateTime, LocalDateTime.now());// 设置安全的更新条件if (updateDTO.getId() != null) {wrapper.eq(User::getId, updateDTO.getId());} else if (StringUtils.isNotBlank(updateDTO.getEmail())) {wrapper.eq(User::getEmail, updateDTO.getEmail());} else if (CollectionUtils.isNotEmpty(updateDTO.getIds())) {wrapper.in(User::getId, updateDTO.getIds());}// 基础安全条件wrapper.eq(User::getDeleted, 0);return this.update(wrapper);}
}
LambdaUpdateWrapper与实体结合:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 实体+LambdaUpdateWrapper混合更新*/public void entityWithWrapper() {// 创建要更新的实体User user = new User();user.setName("张三");user.setAge(30);user.setEmail("zhangsan@example.com");user.setUpdateTime(LocalDateTime.now());// 创建更新条件LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();wrapper.eq(User::getId, 1L).eq(User::getDeleted, 0);// 使用实体+条件进行更新this.update(user, wrapper);// 生成SQL:UPDATE t_user SET name = '张三', age = 30, email = 'zhangsan@example.com', update_time = NOW() // WHERE id = 1 AND deleted = 0}/*** 选择性更新(只更新非空字段)*/public void selectiveUpdate(Long userId, UserUpdateDTO updateDTO) {// 构建实体对象(只设置非空字段)User user = new User();if (StringUtils.isNotBlank(updateDTO.getName())) {user.setName(updateDTO.getName());}if (updateDTO.getAge() != null) {user.setAge(updateDTO.getAge());}if (StringUtils.isNotBlank(updateDTO.getEmail())) {user.setEmail(updateDTO.getEmail());}if (updateDTO.getStatus() != null) {user.setStatus(updateDTO.getStatus());}user.setUpdateTime(LocalDateTime.now());// 构建更新条件LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();wrapper.eq(User::getId, userId).eq(User::getDeleted, 0);this.update(user, wrapper);}/*** 批量实体更新*/public void batchEntityUpdate(List<UserUpdateDTO> updateList) {for (UserUpdateDTO updateDTO : updateList) {if (updateDTO.getId() == null) {continue;}User user = new User();BeanUtils.copyProperties(updateDTO, user);user.setUpdateTime(LocalDateTime.now());LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();wrapper.eq(User::getId, updateDTO.getId()).eq(User::getDeleted, 0);this.update(user, wrapper);}}
}
最佳实践:
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 事务性批量更新*/@Transactional(rollbackFor = Exception.class)public void transactionalBatchUpdate(List<UserUpdateDTO> updateList) {for (UserUpdateDTO updateDTO : updateList) {LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();// 设置更新字段wrapper.set(User::getStatus, updateDTO.getStatus()).set(User::getUpdateTime, LocalDateTime.now()).set(User::getUpdatedBy, updateDTO.getUpdatedBy());// 设置更新条件wrapper.eq(User::getId, updateDTO.getId()).eq(User::getDeleted, 0);boolean success = this.update(wrapper);if (!success) {throw new RuntimeException("更新用户失败:" + updateDTO.getId());}}}/*** 性能优化的批量更新*/public void optimizedBatchUpdate(List<UserUpdateDTO> updateList) {// 按更新类型分组Map<Integer, List<UserUpdateDTO>> groupedUpdates = updateList.stream().collect(Collectors.groupingBy(UserUpdateDTO::getStatus));// 批量更新相同状态的用户for (Map.Entry<Integer, List<UserUpdateDTO>> entry : groupedUpdates.entrySet()) {Integer status = entry.getKey();List<Long> userIds = entry.getValue().stream().map(UserUpdateDTO::getId).collect(Collectors.toList());LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();wrapper.set(User::getStatus, status).set(User::getUpdateTime, LocalDateTime.now()).in(User::getId, userIds).eq(User::getDeleted, 0);this.update(wrapper);}}/*** 条件更新工厂方法*/public LambdaUpdateWrapper<User> createUpdateWrapper() {LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();wrapper.set(User::getUpdateTime, LocalDateTime.now());return wrapper;}/*** 链式更新构建*/public boolean chainUpdate(Long userId, String name, Integer status) {return this.update(this.createUpdateWrapper().set(User::getName, name).set(User::getStatus, status).eq(User::getId, userId).eq(User::getDeleted, 0));}
}
条件构造器高级用法
简要描述:MybatisPlus条件构造器提供了丰富的高级功能,包括复杂SQL构建、自定义SQL片段、函数调用、子查询等,能够满足各种复杂的业务查询需求。
核心概念:
- SQL函数支持:支持数据库内置函数调用
- 自定义SQL片段:支持原生SQL片段嵌入
- 子查询构建:支持复杂的子查询操作
- 聚合查询:支持分组、聚合函数等
- 联表查询:支持多表关联查询
自定义SQL片段与函数调用
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 使用SQL函数*/public void sqlFunctions() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 日期函数wrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", "2023-12").apply("YEAR(create_time) = {0}", 2023).apply("MONTH(create_time) = {0}", 12).apply("DATEDIFF(NOW(), create_time) <= {0}", 30);// 字符串函数wrapper.apply("CHAR_LENGTH(name) > {0}", 2).apply("UPPER(name) LIKE {0}", "%ADMIN%").apply("CONCAT(first_name, ' ', last_name) = {0}", "张 三");// 数学函数wrapper.apply("ABS(salary - {0}) < {1}", 5000, 500).apply("ROUND(salary / 1000, 2) > {0}", 10.5).apply("MOD(id, 2) = {0}", 1); // 查询奇数IDList<User> users = this.list(wrapper);}/*** JSON字段查询*/public void jsonFieldQuery() {QueryWrapper<User> wrapper = new QueryWrapper<>();// JSON_EXTRACT函数wrapper.apply("JSON_EXTRACT(extra_info, '$.age') > {0}", 25).apply("JSON_EXTRACT(extra_info, '$.city') = {0}", "北京").apply("JSON_CONTAINS(tags, {0})", "'\"VIP\"'");// JSON_UNQUOTE函数wrapper.apply("JSON_UNQUOTE(JSON_EXTRACT(extra_info, '$.phone')) LIKE {0}", "138%");// JSON路径查询wrapper.apply("extra_info->'$.preferences[0]' = {0}", "'sports'");List<User> users = this.list(wrapper);}/*** 正则表达式查询*/public void regexQuery() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 邮箱格式验证wrapper.apply("email REGEXP {0}", "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")// 手机号格式验证.apply("phone REGEXP {0}", "^1[3-9][0-9]{9}$")// 身份证号格式验证.apply("id_card REGEXP {0}", "^[1-9][0-9]{5}(18|19|20)[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])[0-9]{3}[0-9Xx]$");List<User> users = this.list(wrapper);}/*** 全文搜索*/public void fullTextSearch() {QueryWrapper<User> wrapper = new QueryWrapper<>();// MySQL全文搜索wrapper.apply("MATCH(name, description) AGAINST({0} IN NATURAL LANGUAGE MODE)", "Java开发").apply("MATCH(name, description) AGAINST({0} IN BOOLEAN MODE)", "+Java +Spring -PHP");List<User> users = this.list(wrapper);}
}
复杂子查询构建
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** EXISTS子查询*/public void existsSubQuery() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 查询有订单的用户wrapper.exists("SELECT 1 FROM t_order o WHERE o.user_id = t_user.id AND o.status = 1")// 查询有角色的用户.exists("SELECT 1 FROM t_user_role ur WHERE ur.user_id = t_user.id")// 查询在指定部门的用户.exists("SELECT 1 FROM t_dept d WHERE d.id = t_user.dept_id AND d.status = 1");List<User> users = this.list(wrapper);}/*** NOT EXISTS子查询*/public void notExistsSubQuery() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 查询没有订单的用户wrapper.notExists("SELECT 1 FROM t_order o WHERE o.user_id = t_user.id")// 查询没有登录记录的用户.notExists("SELECT 1 FROM t_login_log l WHERE l.user_id = t_user.id AND l.create_time > DATE_SUB(NOW(), INTERVAL 30 DAY)");List<User> users = this.list(wrapper);}/*** IN子查询*/public void inSubQuery() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 查询在活跃部门的用户wrapper.inSql("dept_id", "SELECT id FROM t_dept WHERE status = 1 AND employee_count > 10")// 查询有特定权限的用户.inSql("id", "SELECT user_id FROM t_user_permission WHERE permission_code = 'ADMIN'")// 查询最近活跃的用户.inSql("id", "SELECT DISTINCT user_id FROM t_login_log WHERE create_time > DATE_SUB(NOW(), INTERVAL 7 DAY)");List<User> users = this.list(wrapper);}/*** 关联子查询*/public void correlatedSubQuery() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 查询薪资高于部门平均薪资的用户wrapper.apply("salary > (SELECT AVG(salary) FROM t_user u2 WHERE u2.dept_id = t_user.dept_id)")// 查询订单数量最多的用户.apply("(SELECT COUNT(*) FROM t_order o WHERE o.user_id = t_user.id) = " +"(SELECT MAX(order_count) FROM (SELECT COUNT(*) as order_count FROM t_order GROUP BY user_id) tmp)");List<User> users = this.list(wrapper);}/*** 多层嵌套子查询*/public void nestedSubQuery() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 查询在销售额最高的部门工作的用户wrapper.inSql("dept_id", "SELECT dept_id FROM t_user WHERE id IN (" +" SELECT user_id FROM t_order WHERE total_amount = (" +" SELECT MAX(total_amount) FROM t_order" +" )" +")");// 查询管理层级最深的用户wrapper.apply("(SELECT COUNT(*) FROM t_user u2 WHERE u2.manager_id = t_user.id) = (" +" SELECT MAX(subordinate_count) FROM (" +" SELECT COUNT(*) as subordinate_count FROM t_user GROUP BY manager_id" +" ) tmp" +")");List<User> users = this.list(wrapper);}
}
聚合查询与分组
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 基本聚合查询*/public void basicAggregation() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 统计查询wrapper.select("dept_id", "COUNT(*) as user_count","AVG(age) as avg_age","MAX(salary) as max_salary","MIN(salary) as min_salary","SUM(salary) as total_salary").groupBy("dept_id").having("COUNT(*) > {0}", 5).orderByDesc("user_count");List<Map<String, Object>> result = this.listMaps(wrapper);}/*** 复杂聚合查询*/public void complexAggregation() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 多维度统计wrapper.select("dept_id","status","COUNT(*) as count","AVG(CASE WHEN gender = 'M' THEN age END) as avg_male_age","AVG(CASE WHEN gender = 'F' THEN age END) as avg_female_age","SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) as active_count","ROUND(AVG(salary), 2) as avg_salary").groupBy("dept_id", "status").having("COUNT(*) >= {0}", 3).having("AVG(salary) > {0}", 5000).orderByAsc("dept_id").orderByDesc("avg_salary");List<Map<String, Object>> result = this.listMaps(wrapper);}/*** 时间维度聚合*/public void timeAggregation() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 按年月统计wrapper.select("DATE_FORMAT(create_time, '%Y-%m') as month","COUNT(*) as register_count","COUNT(DISTINCT dept_id) as dept_count").groupBy("DATE_FORMAT(create_time, '%Y-%m')").orderByAsc("month");List<Map<String, Object>> monthlyStats = this.listMaps(wrapper);// 按季度统计wrapper.clear();wrapper.select("YEAR(create_time) as year","QUARTER(create_time) as quarter","COUNT(*) as count","AVG(age) as avg_age").groupBy("YEAR(create_time)", "QUARTER(create_time)").orderByAsc("year", "quarter");List<Map<String, Object>> quarterlyStats = this.listMaps(wrapper);}/*** 窗口函数查询(MySQL 8.0+)*/public void windowFunction() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 排名查询wrapper.select("id", "name", "salary", "dept_id","ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) as salary_rank","RANK() OVER (ORDER BY salary DESC) as overall_rank","DENSE_RANK() OVER (PARTITION BY dept_id ORDER BY age) as age_rank").eq("status", 1);List<Map<String, Object>> rankedUsers = this.listMaps(wrapper);// 累计统计wrapper.clear();wrapper.select("id", "name", "salary", "create_time","SUM(salary) OVER (ORDER BY create_time) as cumulative_salary","AVG(salary) OVER (ORDER BY create_time ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) as moving_avg").orderByAsc("create_time");List<Map<String, Object>> cumulativeStats = this.listMaps(wrapper);}
}
联表查询构建
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 手动构建JOIN查询*/public void manualJoinQuery() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 内连接wrapper.select("u.id", "u.name", "u.email", "d.name as dept_name", "r.name as role_name").from("t_user u").innerJoin("t_dept d ON u.dept_id = d.id").leftJoin("t_user_role ur ON u.id = ur.user_id").leftJoin("t_role r ON ur.role_id = r.id").eq("u.status", 1).eq("d.status", 1).isNotNull("r.id");List<Map<String, Object>> result = this.listMaps(wrapper);}/*** 复杂关联查询*/public void complexJoinQuery() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 多表关联统计wrapper.select("d.name as dept_name","COUNT(DISTINCT u.id) as user_count","COUNT(DISTINCT o.id) as order_count","SUM(o.total_amount) as total_sales","AVG(u.salary) as avg_salary").from("t_dept d").leftJoin("t_user u ON d.id = u.dept_id AND u.status = 1").leftJoin("t_order o ON u.id = o.user_id AND o.status = 1").groupBy("d.id", "d.name").having("COUNT(DISTINCT u.id) > {0}", 0).orderByDesc("total_sales");List<Map<String, Object>> deptStats = this.listMaps(wrapper);}/*** 自关联查询*/public void selfJoinQuery() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 查询用户及其直接下属wrapper.select("u1.id as manager_id", "u1.name as manager_name","u2.id as subordinate_id", "u2.name as subordinate_name").from("t_user u1").innerJoin("t_user u2 ON u1.id = u2.manager_id").eq("u1.status", 1).eq("u2.status", 1).orderByAsc("u1.id", "u2.name");List<Map<String, Object>> managerSubordinates = this.listMaps(wrapper);// 查询管理层级wrapper.clear();wrapper.select("u1.id", "u1.name","COUNT(u2.id) as direct_subordinates","(SELECT COUNT(*) FROM t_user WHERE manager_id = u1.id) as total_subordinates").from("t_user u1").leftJoin("t_user u2 ON u1.id = u2.manager_id").groupBy("u1.id", "u1.name").having("COUNT(u2.id) > {0}", 0).orderByDesc("direct_subordinates");List<Map<String, Object>> managers = this.listMaps(wrapper);}
}
动态SQL构建
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 动态条件构建器*/public QueryWrapper<User> buildDynamicWrapper(UserQueryDTO queryDTO) {QueryWrapper<User> wrapper = new QueryWrapper<>();// 基础条件wrapper.eq("deleted", 0);// 动态添加条件Optional.ofNullable(queryDTO.getName()).filter(StringUtils::isNotBlank).ifPresent(name -> {if (queryDTO.isExactMatch()) {wrapper.eq("name", name);} else {wrapper.like("name", name);}});Optional.ofNullable(queryDTO.getStatus()).ifPresent(status -> wrapper.eq("status", status));Optional.ofNullable(queryDTO.getDeptId()).ifPresent(deptId -> wrapper.eq("dept_id", deptId));// 年龄范围if (queryDTO.getMinAge() != null || queryDTO.getMaxAge() != null) {if (queryDTO.getMinAge() != null && queryDTO.getMaxAge() != null) {wrapper.between("age", queryDTO.getMinAge(), queryDTO.getMaxAge());} else if (queryDTO.getMinAge() != null) {wrapper.ge("age", queryDTO.getMinAge());} else {wrapper.le("age", queryDTO.getMaxAge());}}// 时间范围Optional.ofNullable(queryDTO.getCreateTimeStart()).ifPresent(start -> wrapper.ge("create_time", start));Optional.ofNullable(queryDTO.getCreateTimeEnd()).ifPresent(end -> wrapper.le("create_time", end));// 集合条件Optional.ofNullable(queryDTO.getDeptIds()).filter(CollectionUtils::isNotEmpty).ifPresent(deptIds -> wrapper.in("dept_id", deptIds));// 关键字搜索Optional.ofNullable(queryDTO.getKeyword()).filter(StringUtils::isNotBlank).ifPresent(keyword -> {wrapper.and(w -> w.like("name", keyword).or().like("email", keyword).or().like("phone", keyword));});// 排序if (StringUtils.isNotBlank(queryDTO.getOrderBy())) {boolean isAsc = "asc".equalsIgnoreCase(queryDTO.getOrderDirection());wrapper.orderBy(true, isAsc, queryDTO.getOrderBy());} else {wrapper.orderByDesc("create_time");}return wrapper;}/*** 条件构建器工厂*/public static class WrapperBuilder {private QueryWrapper<User> wrapper = new QueryWrapper<>();public static WrapperBuilder create() {return new WrapperBuilder();}public WrapperBuilder baseCondition() {wrapper.eq("deleted", 0);return this;}public WrapperBuilder active() {wrapper.eq("status", 1);return this;}public WrapperBuilder byDept(Long deptId) {if (deptId != null) {wrapper.eq("dept_id", deptId);}return this;}public WrapperBuilder ageRange(Integer minAge, Integer maxAge) {if (minAge != null && maxAge != null) {wrapper.between("age", minAge, maxAge);} else if (minAge != null) {wrapper.ge("age", minAge);} else if (maxAge != null) {wrapper.le("age", maxAge);}return this;}public WrapperBuilder keyword(String keyword) {if (StringUtils.isNotBlank(keyword)) {wrapper.and(w -> w.like("name", keyword).or().like("email", keyword));}return this;}public WrapperBuilder orderByCreateTime() {wrapper.orderByDesc("create_time");return this;}public QueryWrapper<User> build() {return wrapper;}}/*** 使用构建器模式*/public List<User> queryWithBuilder(Long deptId, String keyword) {QueryWrapper<User> wrapper = WrapperBuilder.create().baseCondition().active().byDept(deptId).keyword(keyword).orderByCreateTime().build();return this.list(wrapper);}
}
动态条件构建技巧
简要描述:动态条件构建是MybatisPlus的核心特性之一,能够根据业务需求动态组装查询条件,避免复杂的if-else判断,提高代码的可读性和维护性。
核心概念:
- 条件判断:自动忽略null值和空字符串
- 链式调用:支持流畅的方法链式调用
- 条件组合:支持AND、OR等复杂逻辑组合
- 函数式编程:支持Lambda表达式和函数式接口
- 类型安全:编译时类型检查,避免字段名错误
基础动态条件
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 基础动态查询*/public List<User> dynamicQuery(String name, Integer status, Integer minAge, Integer maxAge) {QueryWrapper<User> wrapper = new QueryWrapper<>();// 自动忽略null值wrapper.eq(StringUtils.isNotBlank(name), "name", name).eq(status != null, "status", status).ge(minAge != null, "age", minAge).le(maxAge != null, "age", maxAge);return this.list(wrapper);}/*** Lambda动态查询*/public List<User> lambdaDynamicQuery(String name, Integer status, List<Long> deptIds) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// 类型安全的动态条件wrapper.like(StringUtils.isNotBlank(name), User::getName, name).eq(status != null, User::getStatus, status).in(CollectionUtils.isNotEmpty(deptIds), User::getDeptId, deptIds);return this.list(wrapper);}/*** 复杂动态条件*/public List<User> complexDynamicQuery(UserQueryDTO queryDTO) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// 基础条件wrapper.eq(User::getDeleted, 0);// 姓名条件(精确匹配或模糊匹配)if (StringUtils.isNotBlank(queryDTO.getName())) {if (queryDTO.isExactMatch()) {wrapper.eq(User::getName, queryDTO.getName());} else {wrapper.like(User::getName, queryDTO.getName());}}// 状态条件wrapper.eq(queryDTO.getStatus() != null, User::getStatus, queryDTO.getStatus());// 年龄范围wrapper.between(queryDTO.getMinAge() != null && queryDTO.getMaxAge() != null,User::getAge, queryDTO.getMinAge(), queryDTO.getMaxAge()).ge(queryDTO.getMinAge() != null && queryDTO.getMaxAge() == null,User::getAge, queryDTO.getMinAge()).le(queryDTO.getMinAge() == null && queryDTO.getMaxAge() != null,User::getAge, queryDTO.getMaxAge());// 部门条件wrapper.in(CollectionUtils.isNotEmpty(queryDTO.getDeptIds()),User::getDeptId, queryDTO.getDeptIds());// 时间范围wrapper.ge(queryDTO.getCreateTimeStart() != null,User::getCreateTime, queryDTO.getCreateTimeStart()).le(queryDTO.getCreateTimeEnd() != null,User::getCreateTime, queryDTO.getCreateTimeEnd());return this.list(wrapper);}
}
条件组合与嵌套
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** AND条件组合*/public List<User> andConditions(String keyword, Integer status, List<Long> deptIds) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// 基础AND条件wrapper.eq(User::getDeleted, 0).eq(status != null, User::getStatus, status).in(CollectionUtils.isNotEmpty(deptIds), User::getDeptId, deptIds);// 关键字搜索(多字段OR)if (StringUtils.isNotBlank(keyword)) {wrapper.and(w -> w.like(User::getName, keyword).or().like(User::getEmail, keyword).or().like(User::getPhone, keyword));}return this.list(wrapper);}/*** OR条件组合*/public List<User> orConditions(String name, String email, String phone) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getDeleted, 0);// 至少满足一个条件wrapper.and(w -> {boolean hasCondition = false;if (StringUtils.isNotBlank(name)) {w.like(User::getName, name);hasCondition = true;}if (StringUtils.isNotBlank(email)) {if (hasCondition) w.or();w.like(User::getEmail, email);hasCondition = true;}if (StringUtils.isNotBlank(phone)) {if (hasCondition) w.or();w.like(User::getPhone, phone);}});return this.list(wrapper);}/*** 复杂嵌套条件*/public List<User> nestedConditions(UserSearchDTO searchDTO) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();// 基础条件wrapper.eq(User::getDeleted, 0);// 复杂嵌套:(name LIKE ? OR email LIKE ?) AND (status = ? OR age > ?)wrapper.and(w1 -> {// 第一组OR条件w1.like(StringUtils.isNotBlank(searchDTO.getKeyword()), User::getName, searchDTO.getKeyword()).or(StringUtils.isNotBlank(searchDTO.getKeyword())).like(StringUtils.isNotBlank(searchDTO.getKeyword()), User::getEmail, searchDTO.getKeyword());}).and(w2 -> {// 第二组OR条件w2.eq(searchDTO.getStatus() != null, User::getStatus, searchDTO.getStatus()).or(searchDTO.getMinAge() != null).gt(searchDTO.getMinAge() != null, User::getAge, searchDTO.getMinAge());});return this.list(wrapper);}/*** 动态嵌套条件构建*/public List<User> dynamicNestedConditions(List<SearchCondition> conditions) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getDeleted, 0);if (CollectionUtils.isNotEmpty(conditions)) {wrapper.and(w -> {for (int i = 0; i < conditions.size(); i++) {SearchCondition condition = conditions.get(i);if (i > 0) {if ("OR".equals(condition.getLogic())) {w.or();}// AND是默认的,不需要显式调用}// 根据条件类型动态构建switch (condition.getType()) {case "eq":w.eq(User::getName, condition.getValue());break;case "like":w.like(User::getName, condition.getValue());break;case "gt":w.gt(User::getAge, condition.getValue());break;case "in":w.in(User::getDeptId, condition.getValues());break;}}});}return this.list(wrapper);}
}
函数式条件构建
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 函数式条件构建*/public List<User> functionalConditions(UserQueryDTO queryDTO) {return this.list(new LambdaQueryWrapper<User>().eq(User::getDeleted, 0).func(wrapper -> {// 姓名条件Optional.ofNullable(queryDTO.getName()).filter(StringUtils::isNotBlank).ifPresent(name -> wrapper.like(User::getName, name));// 状态条件Optional.ofNullable(queryDTO.getStatus()).ifPresent(status -> wrapper.eq(User::getStatus, status));// 年龄范围if (queryDTO.getMinAge() != null || queryDTO.getMaxAge() != null) {wrapper.and(w -> {Optional.ofNullable(queryDTO.getMinAge()).ifPresent(minAge -> w.ge(User::getAge, minAge));Optional.ofNullable(queryDTO.getMaxAge()).ifPresent(maxAge -> w.le(User::getAge, maxAge));});}}));}/*** 条件工厂方法*/public static class ConditionFactory {public static Consumer<LambdaQueryWrapper<User>> nameCondition(String name) {return wrapper -> {if (StringUtils.isNotBlank(name)) {wrapper.like(User::getName, name);}};}public static Consumer<LambdaQueryWrapper<User>> statusCondition(Integer status) {return wrapper -> {if (status != null) {wrapper.eq(User::getStatus, status);}};}public static Consumer<LambdaQueryWrapper<User>> ageRangeCondition(Integer minAge, Integer maxAge) {return wrapper -> {if (minAge != null && maxAge != null) {wrapper.between(User::getAge, minAge, maxAge);} else if (minAge != null) {wrapper.ge(User::getAge, minAge);} else if (maxAge != null) {wrapper.le(User::getAge, maxAge);}};}public static Consumer<LambdaQueryWrapper<User>> deptCondition(List<Long> deptIds) {return wrapper -> {if (CollectionUtils.isNotEmpty(deptIds)) {wrapper.in(User::getDeptId, deptIds);}};}public static Consumer<LambdaQueryWrapper<User>> keywordCondition(String keyword) {return wrapper -> {if (StringUtils.isNotBlank(keyword)) {wrapper.and(w -> w.like(User::getName, keyword).or().like(User::getEmail, keyword).or().like(User::getPhone, keyword));}};}}/*** 使用条件工厂*/public List<User> queryWithFactory(UserQueryDTO queryDTO) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>().eq(User::getDeleted, 0).func(ConditionFactory.nameCondition(queryDTO.getName())).func(ConditionFactory.statusCondition(queryDTO.getStatus())).func(ConditionFactory.ageRangeCondition(queryDTO.getMinAge(), queryDTO.getMaxAge())).func(ConditionFactory.deptCondition(queryDTO.getDeptIds())).func(ConditionFactory.keywordCondition(queryDTO.getKeyword()));return this.list(wrapper);}/*** 链式条件构建器*/public static class ChainConditionBuilder {private LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();public static ChainConditionBuilder create() {return new ChainConditionBuilder().baseCondition();}private ChainConditionBuilder baseCondition() {wrapper.eq(User::getDeleted, 0);return this;}public ChainConditionBuilder name(String name) {wrapper.like(StringUtils.isNotBlank(name), User::getName, name);return this;}public ChainConditionBuilder status(Integer status) {wrapper.eq(status != null, User::getStatus, status);return this;}public ChainConditionBuilder ageRange(Integer minAge, Integer maxAge) {wrapper.between(minAge != null && maxAge != null, User::getAge, minAge, maxAge).ge(minAge != null && maxAge == null, User::getAge, minAge).le(minAge == null && maxAge != null, User::getAge, maxAge);return this;}public ChainConditionBuilder depts(List<Long> deptIds) {wrapper.in(CollectionUtils.isNotEmpty(deptIds), User::getDeptId, deptIds);return this;}public ChainConditionBuilder keyword(String keyword) {if (StringUtils.isNotBlank(keyword)) {wrapper.and(w -> w.like(User::getName, keyword).or().like(User::getEmail, keyword).or().like(User::getPhone, keyword));}return this;}public ChainConditionBuilder timeRange(LocalDateTime start, LocalDateTime end) {wrapper.ge(start != null, User::getCreateTime, start).le(end != null, User::getCreateTime, end);return this;}public ChainConditionBuilder orderBy(String field, boolean isAsc) {if (StringUtils.isNotBlank(field)) {switch (field) {case "name":wrapper.orderBy(true, isAsc, User::getName);break;case "age":wrapper.orderBy(true, isAsc, User::getAge);break;case "createTime":wrapper.orderBy(true, isAsc, User::getCreateTime);break;default:wrapper.orderByDesc(User::getCreateTime);}} else {wrapper.orderByDesc(User::getCreateTime);}return this;}public LambdaQueryWrapper<User> build() {return wrapper;}}/*** 使用链式构建器*/public List<User> queryWithChainBuilder(UserQueryDTO queryDTO) {LambdaQueryWrapper<User> wrapper = ChainConditionBuilder.create().name(queryDTO.getName()).status(queryDTO.getStatus()).ageRange(queryDTO.getMinAge(), queryDTO.getMaxAge()).depts(queryDTO.getDeptIds()).keyword(queryDTO.getKeyword()).timeRange(queryDTO.getCreateTimeStart(), queryDTO.getCreateTimeEnd()).orderBy(queryDTO.getOrderBy(), "asc".equals(queryDTO.getOrderDirection())).build();return this.list(wrapper);}
}
动态排序与分页
@Service
public class UserService extends ServiceImpl<UserMapper, User> {/*** 动态排序*/public List<User> dynamicOrder(String orderBy, String orderDirection) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getDeleted, 0);// 动态排序if (StringUtils.isNotBlank(orderBy)) {boolean isAsc = "asc".equalsIgnoreCase(orderDirection);switch (orderBy.toLowerCase()) {case "name":wrapper.orderBy(true, isAsc, User::getName);break;case "age":wrapper.orderBy(true, isAsc, User::getAge);break;case "salary":wrapper.orderBy(true, isAsc, User::getSalary);break;case "createtime":wrapper.orderBy(true, isAsc, User::getCreateTime);break;default:wrapper.orderByDesc(User::getCreateTime); // 默认排序}} else {wrapper.orderByDesc(User::getCreateTime);}return this.list(wrapper);}/*** 多字段动态排序*/public List<User> multiFieldOrder(List<OrderField> orderFields) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getDeleted, 0);if (CollectionUtils.isNotEmpty(orderFields)) {for (OrderField orderField : orderFields) {boolean isAsc = "asc".equalsIgnoreCase(orderField.getDirection());switch (orderField.getField().toLowerCase()) {case "name":wrapper.orderBy(true, isAsc, User::getName);break;case "age":wrapper.orderBy(true, isAsc, User::getAge);break;case "salary":wrapper.orderBy(true, isAsc, User::getSalary);break;case "createtime":wrapper.orderBy(true, isAsc, User::getCreateTime);break;}}} else {wrapper.orderByDesc(User::getCreateTime);}return this.list(wrapper);}/*** 动态分页查询*/public IPage<User> dynamicPageQuery(UserQueryDTO queryDTO, Integer current, Integer size) {// 构建查询条件LambdaQueryWrapper<User> wrapper = ChainConditionBuilder.create().name(queryDTO.getName()).status(queryDTO.getStatus()).ageRange(queryDTO.getMinAge(), queryDTO.getMaxAge()).depts(queryDTO.getDeptIds()).keyword(queryDTO.getKeyword()).timeRange(queryDTO.getCreateTimeStart(), queryDTO.getCreateTimeEnd()).orderBy(queryDTO.getOrderBy(), "asc".equals(queryDTO.getOrderDirection())).build();// 分页参数Page<User> page = new Page<>(current != null ? current : 1, size != null ? size : 10);return this.page(page, wrapper);}/*** 高级分页查询(支持自定义分页参数)*/public IPage<User> advancedPageQuery(UserQueryDTO queryDTO, PageDTO pageDTO) {// 构建查询条件LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getDeleted, 0);// 动态条件Optional.ofNullable(queryDTO.getName()).filter(StringUtils::isNotBlank).ifPresent(name -> wrapper.like(User::getName, name));Optional.ofNullable(queryDTO.getStatus()).ifPresent(status -> wrapper.eq(User::getStatus, status));Optional.ofNullable(queryDTO.getDeptIds()).filter(CollectionUtils::isNotEmpty).ifPresent(deptIds -> wrapper.in(User::getDeptId, deptIds));// 关键字搜索Optional.ofNullable(queryDTO.getKeyword()).filter(StringUtils::isNotBlank).ifPresent(keyword -> {wrapper.and(w -> w.like(User::getName, keyword).or().like(User::getEmail, keyword).or().like(User::getPhone, keyword));});// 动态排序if (CollectionUtils.isNotEmpty(pageDTO.getOrders())) {for (PageDTO.Order order : pageDTO.getOrders()) {boolean isAsc = "asc".equalsIgnoreCase(order.getDirection());switch (order.getField().toLowerCase()) {case "name":wrapper.orderBy(true, isAsc, User::getName);break;case "age":wrapper.orderBy(true, isAsc, User::getAge);break;case "createtime":wrapper.orderBy(true, isAsc, User::getCreateTime);break;}}} else {wrapper.orderByDesc(User::getCreateTime);}// 分页Page<User> page = new Page<>(pageDTO.getCurrent(), pageDTO.getSize());// 是否查询总数page.setSearchCount(pageDTO.isSearchCount());return this.page(page, wrapper);}
}/*** 查询DTO*/
@Data
public class UserQueryDTO {private String name;private Integer status;private Integer minAge;private Integer maxAge;private List<Long> deptIds;private String keyword;private LocalDateTime createTimeStart;private LocalDateTime createTimeEnd;private String orderBy;private String orderDirection;private boolean exactMatch = false;
}/*** 排序字段*/
@Data
public class OrderField {private String field;private String direction = "asc";
}/*** 分页DTO*/
@Data
public class PageDTO {private Integer current = 1;private Integer size = 10;private boolean searchCount = true;private List<Order> orders;@Datapublic static class Order {private String field;private String direction = "asc";}
}/*** 搜索条件*/
@Data
public class SearchCondition {private String type; // eq, like, gt, in等private String field; // 字段名private Object value; // 单个值private List<Object> values; // 多个值(用于in条件)private String logic = "AND"; // AND, OR
}