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
);
相关推荐
Wang's Blog2 小时前
Java 接入Redis: 服务启动停止与后台运行配置
java·服务器·redis
此时不提桶,更待何时2 小时前
01-04-B-垃圾回收面试与生产事故实战
java·jvm·面试
鹿角片ljp4 小时前
KV Cache 解析
java·算法
captain3764 小时前
网络原理(9)-数据链路层
java·网络协议·java-ee
惊讶的猫5 小时前
意图识别置信度和检索重排的分数
java
caoerzhong5 小时前
仓库管理数字化趋势解读:JeeWMS 开源 Java WMS 视角下的五个演进方向
java·开源
程序员JerrySUN5 小时前
Jetson Edge AI 实战01:Nano、Xavier、Orin 怎么选?Jetson 硬件选型详解【视频讲解】
java·数据库·redis·安全·mybatis
Joy T6 小时前
Spring AI 2.0 Agent 进阶:Memory、State 与 Context Engineering 常见技术全景
java·人工智能·后端·spring·agent入门·agent state
估值探索者6 小时前
【Python量化系统工程化 #08】关了 SSH 就停?systemd 让脚本开机自启 + 异常自动拉起
java·c++·人工智能·分类·数据挖掘