MyBatis 报错:Parameter ‘xxx‘ not found 的原因与解决方案

文章目录

一、问题背景

在开发退款记录查询接口时,需要根据退款主表的 refundGuidList 批量查询退款明细中的应收金额。

本地没报错、生产报错,原因是:本地编译出来的 Mapper class 保留了方法参数名 refundGuidList,生产环境编译/打包后的 class 没保留,所以 MyBatis 只能看到 arg0 / collection / list。

业务代码大致如下:

java 复制代码
List<Long> refundGuidList = dataList.stream()
        .map(RefundRecordVo::getFldRefundGuid)
        .toList();

List<RefundReceivableDto> receivableDtoList =
        esBondRefundDetailMapper.queryReceivableAmountByRefundGuids(refundGuidList);

对应的 MyBatis XML 如下:

xml 复制代码
<select id="queryReceivableAmountByRefundGuids" resultType="com.es.bond.refund.dto.RefundReceivableDto">
    SELECT
        fld_refund_guid AS fldRefundGuid,
        SUM(fld_receivable_amount) AS receivableAmount
    FROM es_bond_refund_detail
    WHERE fld_refund_guid IN
    <foreach collection="refundGuidList"
             item="guid"
             open="("
             separator=","
             close=")">
        #{guid}
    </foreach>
    GROUP BY fld_refund_guid
</select>

启动接口后,程序报错:

text 复制代码
org.apache.ibatis.binding.BindingException: 
Parameter 'refundGuidList' not found. 
Available parameters are [arg0, collection, list]

二、问题原因

从报错信息可以看到:

text 复制代码
Available parameters are [arg0, collection, list]

说明 MyBatis 当前能识别的参数名只有:

text 复制代码
arg0
collection
list

但是 XML 中使用的是:

xml 复制代码
<foreach collection="refundGuidList">

也就是说,XML 中使用了 refundGuidList,但是 Mapper 接口方法中并没有通过 @Param 显式声明这个参数名。

如果 Mapper 接口是这样写的:

java 复制代码
List<RefundReceivableDto> queryReceivableAmountByRefundGuids(List<Long> refundGuidList);

那么对于单个 List 参数,MyBatis 默认不会识别 refundGuidList 这个名字,而是默认使用:

text 复制代码
list
collection
arg0

所以就会出现参数找不到的问题。


三、解决方案

方案一:推荐使用 @Param

修改 Mapper 接口方法:

java 复制代码
import org.apache.ibatis.annotations.Param;

List<RefundReceivableDto> queryReceivableAmountByRefundGuids(
        @Param("refundGuidList") List<Long> refundGuidList
);

XML 保持不变:

xml 复制代码
<foreach collection="refundGuidList"
         item="guid"
         open="("
         separator=","
         close=")">
    #{guid}
</foreach>

这样 MyBatis 就可以正确识别 refundGuidList 参数。


方案二:修改 XML 中的 collection 名称

如果不想修改 Mapper 接口,也可以把 XML 改成 MyBatis 默认识别的参数名:

xml 复制代码
<foreach collection="list"
         item="guid"
         open="("
         separator=","
         close=")">
    #{guid}
</foreach>

完整 SQL:

xml 复制代码
<select id="queryReceivableAmountByRefundGuids" resultType="com.es.bond.refund.dto.RefundReceivableDto">
    SELECT
        fld_refund_guid AS fldRefundGuid,
        SUM(fld_receivable_amount) AS receivableAmount
    FROM es_bond_refund_detail
    WHERE fld_refund_guid IN
    <foreach collection="list"
             item="guid"
             open="("
             separator=","
             close=")">
        #{guid}
    </foreach>
    GROUP BY fld_refund_guid
</select>

更推荐第一种方式。


四、最终代码

Mapper 接口:

java 复制代码
List<RefundReceivableDto> queryReceivableAmountByRefundGuids(
        @Param("refundGuidList") List<Long> refundGuidList
);

XML:

xml 复制代码
<select id="queryReceivableAmountByRefundGuids" resultType="com.es.bond.refund.dto.RefundReceivableDto">
    SELECT
        fld_refund_guid AS fldRefundGuid,
        SUM(fld_receivable_amount) AS receivableAmount
    FROM es_bond_refund_detail
    WHERE fld_refund_guid IN
    <foreach collection="refundGuidList"
             item="guid"
             open="("
             separator=","
             close=")">
        #{guid}
    </foreach>
    GROUP BY fld_refund_guid
</select>

Service 层调用:

java 复制代码
List<Long> refundGuidList = dataList.stream()
        .map(RefundRecordVo::getFldRefundGuid)
        .filter(Objects::nonNull)
        .toList();

if (CollectionUtils.isEmpty(refundGuidList)) {
    return Result.ok();
}

List<RefundReceivableDto> receivableDtoList =
        esBondRefundDetailMapper.queryReceivableAmountByRefundGuids(refundGuidList);

五、额外注意点

如果 refundGuidList 为空,SQL 可能会变成:

sql 复制代码
WHERE fld_refund_guid IN ()

这会导致 SQL 语法错误。

所以在调用 Mapper 前,最好先判断集合是否为空:

java 复制代码
if (CollectionUtils.isEmpty(refundGuidList)) {
    return Result.ok();
}

另外,如果需要返回分页结构,不建议直接返回空的 Result.ok(),最好返回完整的分页对象,避免前端解析异常。


六、总结

这次报错的核心原因是:

MyBatis XML 中使用的参数名,与 Mapper 接口中实际传入的参数名不一致。

对于单个 List 参数:

如果没有加 @Param,MyBatis 默认参数名是:

text 复制代码
list、collection、arg0

如果 XML 中想使用自定义名称,比如:

xml 复制代码
collection="refundGuidList"

就必须在 Mapper 接口中添加:

java 复制代码
@Param("refundGuidList")

最终推荐写法:

java 复制代码
List<RefundReceivableDto> queryReceivableAmountByRefundGuids(
        @Param("refundGuidList") List<Long> refundGuidList
);
相关推荐
何以解忧,唯有..25 分钟前
LangChain 工具调用(Tool Calling)实战指南
java·前端·langchain
QQ_21696290961 小时前
【源码编号:project79475】SpringBoot校内二手交易平台:商品发布、分类检索、留言交流、订单管理全流程实战
java·spring boot·后端
前端 贾公子2 小时前
第09章:上下文与记忆 (2)
java·服务器·前端
2601_962203512 小时前
Java进阶07集合(续)
java·开发语言
郑州光合科技余经理2 小时前
本地生活服务系统:模块边界与结算字段怎么拆
java·开发语言·前端·后端·系统架构·uni-app·php
roman_日积跬步-终至千里3 小时前
【数据治理(6)】DataOps 不是调度工具,而是让数据产品长期可信的运行机制
java·服务器·网络
落魄大学生之流水线上谋生计3 小时前
LangGraph 基本用法指南
java·windows·python·langchain
2601_962128413 小时前
SpringBoot篇(缓存层)
java·spring boot·缓存
Dovis(誓平步青云)3 小时前
折叠屏悬停看视频,上半屏和下半屏应该各做什么
android·java·服务器·开发语言·安全·音视频
2501_937860944 小时前
Java多线程初阶(下)—— synchronized、volatile、wait/notify与经典并发工具
java·开发语言·jvm