当前位置: 首页 > ops >正文

Spring Boot中MyBatis Plus的LambdaQueryWrapper查询异常排查与解决

前言

作为一名后端开发者,日常开发中经常使用Spring Boot框架配合MyBatis Plus进行数据库操作。在项目中,我们通常会使用LambdaQueryWrapper来构建动态查询条件,避免SQL注入和提高代码可读性。但有一次,我在使用LambdaQueryWrapper时遇到了一个奇怪的问题:明明按照逻辑拼接了查询条件,却始终无法获取到预期的数据。这个问题让我花费了不少时间去排查和解决,最终找到了原因并总结了一些经验教训。

问题现象

我负责维护一个用户管理模块,其中有一个需求是根据用户的手机号和状态进行模糊搜索。代码如下:

public List<User> searchUsers(String phone, Integer status) {return userMapper.selectList(new LambdaQueryWrapper<User>().like(StringUtils.isNotBlank(phone), User::getPhone, phone).eq(status != null, User::getStatus, status));
}

在测试过程中,我发现当传入phone参数时,虽然数据库中有匹配的记录,但查询结果总是为空。而当我直接写死查询条件时,比如.like(User::getPhone, "138"),却能正常返回数据。这说明问题可能出在动态条件拼接上。

问题分析

首先,我怀疑是StringUtils.isNotBlank(phone)这个判断有问题。如果phone为空,应该不会拼接like条件。但经过日志打印,发现即使phone不为空,like条件也没有被正确添加进去。

接下来,我查看了MyBatis Plus的文档,发现LambdaQueryWrapperlike方法有多种重载形式,包括带条件判断的版本。例如:

.like(boolean condition, String column, Object value)

也就是说,只有当第一个参数为true时,才会将该条件拼接到SQL中。因此,我检查了StringUtils.isNotBlank(phone)是否返回true。通过打印日志,确认phone确实非空,所以这个条件应该是成立的。

那为什么like条件没有生效呢?我开始怀疑可能是字段名或方法引用的问题。比如,User::getPhone是否正确映射到了数据库字段?我查看了实体类的定义:

@Data
public class User {private Long id;private String phone;private Integer status;
}

看起来没问题。那是不是MyBatis Plus的字段映射配置有问题?我检查了application.yml中的MyBatis Plus配置,确认了map-underscore-to-camel-case: true,即自动将数据库的下划线字段映射为Java驼峰命名,这应该也没问题。

排查步骤

第一步:验证条件拼接是否成功

我修改了代码,手动输出生成的SQL语句,看看是否包含了预期的like条件:

public List<User> searchUsers(String phone, Integer status) {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();if (StringUtils.isNotBlank(phone)) {wrapper.like(User::getPhone, phone);}if (status != null) {wrapper.eq(User::getStatus, status);}System.out.println(wrapper.getTargetSql());return userMapper.selectList(wrapper);
}

运行后,输出的SQL是:

SELECT * FROM user WHERE status = ?

这说明like条件根本没有被添加进去!这是怎么回事?难道是LambdaQueryWrapperlike方法在某些情况下失效了?

第二步:尝试使用传统方式拼接条件

为了进一步验证问题,我改用传统的query().like()方式,而不是LambdaQueryWrapper

public List<User> searchUsers(String phone, Integer status) {return userMapper.selectList(new Query<User>().like(StringUtils.isNotBlank(phone), "phone", phone).eq(status != null, "status", status));
}

这次,查询结果正常了。这说明问题可能出在LambdaQueryWrapper的使用方式上。

第三步:查找MyBatis Plus的源码或相关Issue

我查阅了MyBatis Plus的官方文档和GitHub上的Issue,发现有一个类似的提问:

LambdaQueryWrapperlike方法在某些情况下无法正确拼接条件

有人提到,当使用like(boolean condition, SFunction<T, ?> column, Object value)时,column参数必须是一个有效的SFunction表达式。我检查了自己的代码,发现User::getPhone是正确的,没有语法错误。

第四步:尝试简化条件表达式

我尝试将User::getPhone改为直接字符串,看是否能正常工作:

.wrapper.like("phone", phone);

结果仍然失败。这说明问题不是出在表达式本身,而是出在条件拼接逻辑上。

第五步:调试LambdaQueryWrapper内部逻辑

我决定在LambdaQueryWrapperlike方法中打上断点,查看其执行流程。发现当conditiontrue时,确实调用了addCondition方法,但最终生成的SQL中并没有包含like条件。

这时候,我意识到可能是LambdaQueryWrapper的某些配置或依赖版本问题。我检查了pom.xml,发现MyBatis Plus的版本是3.4.2,而最新稳定版本是3.5.3。于是,我升级了MyBatis Plus的版本,问题解决了。

总结

这次Bug的排查过程让我深刻体会到,在使用LambdaQueryWrapper时,一定要注意以下几点:

  1. 确保boolean conditiontrue时才拼接条件;
  2. 检查SFunction表达式是否正确,确保字段映射无误;
  3. 如果遇到奇怪的查询问题,可以尝试打印生成的SQL语句,方便定位问题;
  4. 注意MyBatis Plus的版本兼容性,必要时升级以修复已知问题。

总的来说,这是一个典型的“看似简单,实则复杂”的问题,它提醒我们在使用高级框架时,不能只依赖表面的API,还要理解其底层实现机制,并结合实际测试进行验证。

http://www.xdnf.cn/news/19747.html

相关文章:

  • 外网获取瀚高.NET驱动dll方法和使用案例
  • Axure文件上传高保真交互原型:实现Web端真实上传体验
  • NodeJS配置镜像仓局
  • k8s的SidecarSet配置和initContainers
  • 【明道云】[工作表控件4] 邮箱控件的输入校验与业务应用
  • RAG|| LangChain || LlamaIndex || RAGflow
  • HTML `<datalist>`:原生下拉搜索框,无需 JS 也能实现联想功能
  • 用 “走楼梯” 讲透动态规划!4 个前端场景 + 4 道 LeetCode 题手把手教
  • 戴尔笔记本电池健康度检测、无电池开机测试与更换电池全流程记录
  • 孩子玩手机都近视了,怎样限制小孩的手机使用时长?
  • 你只需输入一句话,MoneyPrinterTurbo直接给你输出一个视频
  • 小说、漫剧小程序系统开发:独立部署,源码交付
  • SpringBoot Web 入门指南:从零搭建第一个SpringBoot程序
  • 【leetcode】200. 岛屿数量
  • 有限元方法中的数值技术:预处理共轭梯度法 PCG (2)
  • 【Cursor-Gpt-5-high】StackCube-v1 任务训练结果不稳定性的分析
  • 关于linux网络编程——4
  • 醋酸铕:点亮现代生活的“隐形之光“
  • HTML元素周期表
  • 【C++】C++入门—(中)
  • ASP.NET Web Forms 实战:用 RadioButton 打造“性别/称谓选择”表单的最佳实践
  • 【数据结构】1绪论
  • 【Qt中信号槽连接connect有接收者和无接收者的区别】
  • 执行一条select语句期间发生了什么?
  • 常用符号 Emoji 对照表——Unicode UTF-8
  • CSS Sass Less 样式.xxx讲解
  • SpringMVC的请求接收与结果响应
  • 华为HCIE数通含金量所剩无几?考试难度加大?
  • 数据库选择有讲究?SQLite、PostgreSQL还是MySQL?
  • 电脑接入企业中的网线,为啥网卡上面显示AD域名