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
);
相关推荐
行思理29 分钟前
微信支付“商家转账用户确认模式”,新手教程
java·开发语言·微信
空中湖1 小时前
Spring AI RAG 完整实战:从零搭建企业知识库问答系统
java·人工智能·spring
Ai拆代码的曹操1 小时前
K8s Pod Pending 逐层排查:从 FailedScheduling 到 PVC StorageClass 不存在的实战记录
java·linux·kubernetes
什巳2 小时前
JAVA练习306- 翻转二叉树
java·数据结构·算法·leetcode
wangbing11252 小时前
JPA下自定义主键
java·linux·服务器
扎Zn了老Fe3 小时前
MyBatis-Plus必知必会:告别低效CRUD,高效开发持久层
后端·mybatis
plainGeekDev3 小时前
NullPointerException → Kotlin 空安全
android·java·kotlin
想做小南娘,发现自己是女生喵4 小时前
第 2 章 顺序表和 vector
java·数据结构·算法
CHANG_THE_WORLD5 小时前
6.多线程的TCP通信
java·网络·tcp/ip
sun03226 小时前
【笔记】Spring MVC 相关介绍
java·spring·mvc