🚀 Spring Data JPA 参数陷阱:从 500 错误到完美解决的奇妙之旅 🌟
嘿,各位技术冒险家!👋 今天我要带你们走进一场 Spring Data JPA 的"参数迷雾"救援行动------从一个让人抓狂的 500 错误,到最终找到真相并解决的全过程!💪 这篇博客不仅有干货,还有代码、流程图和一点小吐槽,快系好安全带,跟我一起跳进这个技术坑吧!😎
🐞 第一幕:500 错误的"神秘来信"
问题登场!😱
我在开发一个分页查询接口,信心满满地丢了个测试 JSON:
json
{
"field": "",
"page": 0,
"size": 10,
"value": null
}
结果,服务器毫不留情地回了我一个 500 错误:
sql
"At least 2 parameter(s) provided but only 1 parameter(s) present in query."
啥?参数不匹配?我直接懵圈了。🤦♂️
🔍 第二幕:代码探秘与日志线索
我的代码长啥样?🧐
先看看控制器:
java
@PostMapping("/listInviteCodeByPageWithSearch")
public BaseResult listInviteCodeByPageWithSearch(
@SessionAttribute("adminId") Integer adminId,
@Valid @RequestBody PageWithSearch pageWithSearch) {
try {
Page<InviteCode> inviteCodePage = inviteCodeService.findPaginatedInviteCodeByAdminIdAndSearch(adminId, pageWithSearch);
return BaseResult.success(inviteCodePage);
} catch (Exception e) {
return BaseResult.failure(500, "分页查询失败:" + e.getMessage());
}
}
再看服务层逻辑:
java
public Page<InviteCode> findPaginatedInviteCodeByAdminIdAndSearch(Integer adminId, PageWithSearch pageWithSearch) {
PageRequest pageRequest = PageRequest.of(pageWithSearch.getPage(), pageWithSearch.getPageSize());
String field = pageWithSearch.getField();
String value = pageWithSearch.getValue();
if (!StringUtils.isEmpty(field) && !StringUtils.isEmpty(value)) {
return inviteCodeRepository.findPaginatedInviteCodeByAdminIdAndFieldAndValue(adminId, field, value, pageRequest);
} else {
return inviteCodeRepository.findByAdminId(adminId, pageRequest);
}
}
Repository 接口里有个关键方法:
java
Page<InviteCode> findByAdminId(Integer adminId, PageRequest pageRequest);
日志说了啥?🕵️♂️
我加了日志,输出是这样的:
sql
2025-03-18 21:05:15.840 INFO : Calling findByAdminId
param:adminId args:7
param:pageWithSearch args:PageWithSearch@22e239cd
- 确认调用了
findByAdminId
。 - 参数:
adminId = 7
,pageRequest
基于page=0, size=10
。
一切看起来正常,可为啥报错呢?🤨
🔧 第三幕:揪出元凶,解决问题!
真相大白!💡
问题出在 findByAdminId
的签名:
java
Page<InviteCode> findByAdminId(Integer adminId, PageRequest pageRequest);
- Spring Data JPA 期待分页参数是
Pageable
,而不是具体的PageRequest
。 - 当我用了
PageRequest
,JPA 误以为它是一个查询参数,导致它认为"需要 2 个参数(adminId
和pageRequest
)",但实际查询只绑定了adminId
,于是报错了!
Mermaid 流程图:错误发生过程
输入 JSON: field='', value=null 服务层: 判断条件不成立 调用 findByAdminId(adminId, pageRequest) JPA 解析: adminId=?1, pageRequest=?2 生成 SQL: WHERE admin_id=?1 错误: 参数数量不匹配
修复方案 🛠️
把 PageRequest
改成 Pageable
,问题迎刃而解:
java
Page<InviteCode> findByAdminId(Integer adminId, Pageable pageable);
服务层调用保持不变(PageRequest
兼容 Pageable
):
java
PageRequest pageRequest = PageRequest.of(pageWithSearch.getPage(), pageWithSearch.getPageSize());
return inviteCodeRepository.findByAdminId(adminId, pageRequest);
再次测试,500 错误消失,数据正常返回!🎉
修复后的流程图
输入 JSON: field='', value=null 服务层: 判断条件不成立 调用 findByAdminId(adminId, pageable) JPA 解析: adminId=?1, pageable=分页参数 生成 SQL: WHERE admin_id=?1 LIMIT 10 OFFSET 0 成功返回分页数据
🌈 第四幕:经验教训与总结
这次我学到了啥?💡
- Spring Data JPA 的分页规范 :分页参数必须用
Pageable
,别自作主张用PageRequest
! - 调试神器:日志 + 流程图,快速定位问题。
- 细心点:一个小小的参数类型,就能引发大麻烦。
小建议 🌟
-
开启 SQL 日志 :看看 JPA 到底生成了啥:
propertiesspring.jpa.show-sql=true logging.level.org.hibernate.SQL=DEBUG
-
用
Specification
:动态查询更灵活,比如:javaSpecification<InviteCode> spec = (root, query, cb) -> cb.equal(root.get("adminId"), adminId);
🎬 尾声
从 500 错误的迷雾到真相大白,这趟旅程让我又爱又恨 Spring Data JPA。希望这篇博客能帮你在开发路上少踩坑!有问题欢迎留言,咱们一起聊技术!✌️
