JeecgBoot MybatisPlus高级用法:Lambda查询+分页插件
引言
在企业级应用开发中,高效的数据查询和分页处理是提升系统性能的关键。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 性能优化建议
- 索引优化: 为频繁查询的字段建立合适索引
- 分页大小: 合理设置pageSize,避免一次查询过多数据
- 字段选择: 使用select()方法指定需要查询的字段
- 批量操作: 使用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的高级用法,能够在实际项目中灵活运用这些技巧,提升开发效率和应用性能。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



