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
);
相关推荐
一条泥憨鱼1 小时前
Java网络编程:Socket通信从入门到起飞
java·开发语言·网络·网络编程
西安邮电大学1 小时前
分布式锁三种实现
java·redis·后端·其他·面试
码不停蹄的玄黓1 小时前
SpringBoot 实现自定义注解
java·spring boot·spring
施棠海1 小时前
自定义并可深度定制的数字滚动选择器完整源代码与相关注意事项
java·开发语言
2601_961194021 小时前
2026六级词汇资料电子版|大学英语六级核心词汇PDF
java·spring·eclipse·pdf·tomcat·hibernate
布朗克1681 小时前
18 面向对象综合实战——设计一个图书管理系统
java·面试·职场和发展·面向对象实战
码不停蹄的玄黓2 小时前
旁路缓存(Cache-Aside,CA)
java·开发语言
NGINX开源社区2 小时前
NGINX Ingress Controller 中的 Cache Policy:VirtualServer 实战指南
java·前端·nginx
lld9510272 小时前
(三)本地策略框架
java·服务器·数据库