JeecgBoot MybatisPlus高级用法:Lambda查询+分页插件

JeecgBoot MybatisPlus高级用法:Lambda查询+分页插件

【免费下载链接】JeecgBoot 🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~ 【免费下载链接】JeecgBoot 项目地址: https://gitcode.com/jeecgboot/JeecgBoot

引言

在企业级应用开发中,高效的数据查询和分页处理是提升系统性能的关键。JeecgBoot作为一款优秀的企业级低代码平台,深度集成了MybatisPlus,提供了强大的Lambda查询和分页插件功能。本文将深入探讨JeecgBoot中MybatisPlus的高级用法,帮助开发者掌握高效的数据库操作技巧。

一、MybatisPlus配置解析

1.1 核心配置类

JeecgBoot通过MybatisPlusSaasConfig类统一配置MybatisPlus:

@Configuration
@MapperScan(value={"org.jeecg.**.mapper*"})
public class MybatisPlusSaasConfig {
    
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        
        // 租户拦截器
        interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {
            @Override
            public Expression getTenantId() {
                String tenantId = TenantContext.getTenant();
                return new LongValue(tenantId);
            }
        }));
        
        // 分页插件 - 支持多种数据库类型
        DbType dbType = getDatabaseType();
        if (dbType == DbType.SQL_SERVER || dbType == DbType.SQL_SERVER2005) {
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.SQL_SERVER2005));
        } else {
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        }
        
        // 乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        
        return interceptor;
    }
}

1.2 配置特性说明

配置项说明默认值
租户隔离支持多租户数据隔离开启
分页插件自动适配不同数据库自动检测
乐观锁支持@Version注解开启
动态表名支持表名动态切换支持

二、Lambda查询高级用法

2.1 基础Lambda查询

// 等值查询
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysUser::getUsername, "admin")
           .eq(SysUser::getStatus, 1);

// 模糊查询
queryWrapper.like(SysUser::getRealname, "张")
           .likeRight(SysUser::getPhone, "138");

// 范围查询
queryWrapper.between(SysUser::getCreateTime, startDate, endDate)
           .gt(SysUser::getAge, 18);

2.2 复杂条件组合

// AND/OR条件组合
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.and(wq -> wq.eq(SysUser::getStatus, 1).or().eq(SysUser::getStatus, 2))
      .or(wq -> wq.like(SysUser::getRealname, "李").and(w -> w.gt(SysUser::getAge, 25)));

// IN查询
List<String> statusList = Arrays.asList("1", "2", "3");
wrapper.in(SysUser::getStatus, statusList);

// NULL值处理
wrapper.isNull(SysUser::getDeleteTime)
      .isNotNull(SysUser::getUpdateTime);

2.3 关联查询示例

// 用户角色关联查询
LambdaQueryWrapper<SysUserRole> roleWrapper = new LambdaQueryWrapper<>();
roleWrapper.eq(SysUserRole::getUserId, userId)
          .select(SysUserRole::getRoleId);

List<SysUserRole> userRoles = sysUserRoleService.list(roleWrapper);
List<String> roleIds = userRoles.stream()
                               .map(SysUserRole::getRoleId)
                               .collect(Collectors.toList());

// 基于角色ID查询角色信息
if (!roleIds.isEmpty()) {
    LambdaQueryWrapper<SysRole> roleQuery = new LambdaQueryWrapper<>();
    roleQuery.in(SysRole::getId, roleIds);
    List<SysRole> roles = sysRoleService.list(roleQuery);
}

三、分页插件深度应用

3.1 基础分页查询

// 分页查询用户列表
@GetMapping("/list")
public Result<IPage<SysUser>> queryPageList(
        @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
        @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
        HttpServletRequest req) {
    
    // 构建查询条件
    QueryWrapper<SysUser> queryWrapper = QueryGenerator.initQueryWrapper(user, req.getParameterMap());
    
    // 执行分页查询
    return sysUserService.queryPageList(req, queryWrapper, pageSize, pageNo);
}

3.2 Lambda分页查询

// Lambda风格分页查询
public IPage<SysUser> queryUsersByCondition(UserQueryDTO queryDTO) {
    Page<SysUser> page = new Page<>(queryDTO.getPageNo(), queryDTO.getPageSize());
    
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    
    // 动态条件构建
    if (StringUtils.isNotBlank(queryDTO.getUsername())) {
        wrapper.like(SysUser::getUsername, queryDTO.getUsername());
    }
    
    if (queryDTO.getStatus() != null) {
        wrapper.eq(SysUser::getStatus, queryDTO.getStatus());
    }
    
    if (queryDTO.getStartTime() != null && queryDTO.getEndTime() != null) {
        wrapper.between(SysUser::getCreateTime, queryDTO.getStartTime(), queryDTO.getEndTime());
    }
    
    // 排序
    wrapper.orderByDesc(SysUser::getCreateTime);
    
    return sysUserService.page(page, wrapper);
}

3.3 自定义分页查询

// 自定义SQL分页查询
public IPage<UserVO> queryCustomPage(UserQueryDTO queryDTO) {
    Page<UserVO> page = new Page<>(queryDTO.getPageNo(), queryDTO.getPageSize());
    
    return sysUserMapper.selectCustomUserPage(page, queryDTO);
}

// Mapper接口定义
@Select("SELECT u.*, d.depart_name FROM sys_user u " +
        "LEFT JOIN sys_user_depart ud ON u.id = ud.user_id " +
        "LEFT JOIN sys_depart d ON ud.depart_id = d.id " +
        "WHERE u.status = #{status} " +
        "ORDER BY u.create_time DESC")
IPage<UserVO> selectCustomUserPage(Page<UserVO> page, @Param("status") Integer status);

四、高级查询技巧

4.1 动态SQL构建

// 动态条件构建工具类
public class QueryBuilder {
    
    public static LambdaQueryWrapper<SysUser> buildUserQuery(UserQueryDTO queryDTO) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        
        // 用户名模糊查询
        if (StringUtils.isNotBlank(queryDTO.getKeyword())) {
            wrapper.and(wq -> wq.like(SysUser::getUsername, queryDTO.getKeyword())
                               .or()
                               .like(SysUser::getRealname, queryDTO.getKeyword()));
        }
        
        // 状态过滤
        if (queryDTO.getStatus() != null) {
            wrapper.eq(SysUser::getStatus, queryDTO.getStatus());
        }
        
        // 时间范围
        if (queryDTO.getStartTime() != null) {
            wrapper.ge(SysUser::getCreateTime, queryDTO.getStartTime());
        }
        if (queryDTO.getEndTime() != null) {
            wrapper.le(SysUser::getCreateTime, queryDTO.getEndTime());
        }
        
        return wrapper;
    }
}

4.2 性能优化技巧

// 1. 选择性字段查询
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.select(SysUser::getId, SysUser::getUsername, SysUser::getRealname)
      .eq(SysUser::getStatus, 1);

// 2. 避免N+1查询问题
public List<UserWithDepartDTO> getUsersWithDepartInfo(List<String> userIds) {
    // 批量查询部门信息
    Map<String, String> userDepartMap = sysUserDepartService.getUserDepartMap(userIds);
    
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    wrapper.in(SysUser::getId, userIds);
    
    List<SysUser> users = sysUserService.list(wrapper);
    
    return users.stream().map(user -> {
        UserWithDepartDTO dto = new UserWithDepartDTO();
        BeanUtils.copyProperties(user, dto);
        dto.setDepartName(userDepartMap.get(user.getId()));
        return dto;
    }).collect(Collectors.toList());
}

五、实战案例

5.1 用户管理分页查询

// 用户分页查询服务实现
@Service
public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Override
    public Result<IPage<SysUser>> queryPageList(HttpServletRequest req, 
                                              QueryWrapper<SysUser> queryWrapper,
                                              Integer pageSize, Integer pageNo) {
        
        Page<SysUser> page = new Page<>(pageNo, pageSize);
        
        // 租户隔离处理
        if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
            String tenantId = TenantContext.getTenant();
            List<String> userIds = userTenantService.getUserIdsByTenantId(Integer.valueOf(tenantId));
            if (CollectionUtils.isNotEmpty(userIds)) {
                queryWrapper.in("id", userIds);
            }
        }
        
        IPage<SysUser> pageList = this.page(page, queryWrapper);
        return Result.OK(pageList);
    }
    
    // Lambda风格分页查询
    public IPage<SysUser> queryUsersByLambda(UserQueryDTO queryDTO) {
        Page<SysUser> page = new Page<>(queryDTO.getPageNo(), queryDTO.getPageSize());
        
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        
        // 构建动态查询条件
        if (StringUtils.isNotBlank(queryDTO.getUsername())) {
            wrapper.like(SysUser::getUsername, queryDTO.getUsername());
        }
        
        if (StringUtils.isNotBlank(queryDTO.getRealname())) {
            wrapper.like(SysUser::getRealname, queryDTO.getRealname());
        }
        
        if (queryDTO.getStatus() != null) {
            wrapper.eq(SysUser::getStatus, queryDTO.getStatus());
        }
        
        // 排序
        wrapper.orderByDesc(SysUser::getCreateTime);
        
        return this.page(page, wrapper);
    }
}

5.2 复杂业务场景

// 多表关联分页查询
public IPage<UserDetailVO> getUserDetailPage(UserQueryDTO queryDTO) {
    Page<UserDetailVO> page = new Page<>(queryDTO.getPageNo(), queryDTO.getPageSize());
    
    return sysUserMapper.selectUserDetailPage(page, queryDTO);
}

// Mapper XML配置
<select id="selectUserDetailPage" resultType="UserDetailVO">
    SELECT 
        u.id,
        u.username,
        u.realname,
        u.phone,
        u.email,
        u.status,
        u.create_time,
        GROUP_CONCAT(DISTINCT r.role_name) as role_names,
        GROUP_CONCAT(DISTINCT d.depart_name) as depart_names
    FROM sys_user u
    LEFT JOIN sys_user_role ur ON u.id = ur.user_id
    LEFT JOIN sys_role r ON ur.role_id = r.id
    LEFT JOIN sys_user_depart ud ON u.id = ud.user_id
    LEFT JOIN sys_depart d ON ud.depart_id = d.id
    <where>
        <if test="queryDTO.keyword != null and queryDTO.keyword != ''">
            AND (u.username LIKE CONCAT('%', #{queryDTO.keyword}, '%') 
                 OR u.realname LIKE CONCAT('%', #{queryDTO.keyword}, '%'))
        </if>
        <if test="queryDTO.status != null">
            AND u.status = #{queryDTO.status}
        </if>
    </where>
    GROUP BY u.id
    ORDER BY u.create_time DESC
</select>

六、最佳实践与注意事项

6.1 性能优化建议

  1. 索引优化: 为频繁查询的字段建立合适索引
  2. 分页大小: 合理设置pageSize,避免一次查询过多数据
  3. 字段选择: 使用select()方法指定需要查询的字段
  4. 批量操作: 使用batch操作减少数据库连接次数

6.2 常见问题解决

// 1. 分页总数查询慢问题
Page<SysUser> page = new Page<>(1, 10);
page.setSearchCount(false); // 不查询总数

// 2. 大数据量分页优化
// 使用基于游标的分页或者基于上次查询最后一条记录的分页

// 3. 内存溢出预防
// 设置合理的分页大小,避免一次性加载过多数据

6.3 监控与调试

// 开启SQL日志监控
# application.yml
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

// 性能监控
@Bean
public PerformanceInterceptor performanceInterceptor() {
    PerformanceInterceptor interceptor = new PerformanceInterceptor();
    interceptor.setMaxTime(1000); // SQL执行最大时间,单位ms
    interceptor.setFormat(true);  // 是否格式化SQL
    return interceptor;
}

总结

JeecgBoot集成的MybatisPlus提供了强大的Lambda查询和分页功能,通过合理的配置和使用技巧,可以显著提升开发效率和系统性能。掌握这些高级用法,能够帮助开发者更好地应对复杂业务场景,构建高性能的企业级应用。

关键要点回顾:

  • Lambda查询提供类型安全的查询条件构建
  • 分页插件自动适配多种数据库类型
  • 动态SQL构建增强查询灵活性
  • 性能优化是提升用户体验的关键

通过本文的深入解析和实战案例,相信您已经掌握了JeecgBoot中MybatisPlus的高级用法,能够在实际项目中灵活运用这些技巧,提升开发效率和应用性能。

【免费下载链接】JeecgBoot 🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~ 【免费下载链接】JeecgBoot 项目地址: https://gitcode.com/jeecgboot/JeecgBoot

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值