文章目录
- 一、问题背景
- 二、问题原因
- 三、解决方案
-
- [方案一:推荐使用 `@Param`](#方案一:推荐使用
@Param) - [方案二:修改 XML 中的 collection 名称](#方案二:修改 XML 中的 collection 名称)
- [方案一:推荐使用 `@Param`](#方案一:推荐使用
- 四、最终代码
- 五、额外注意点
- 六、总结
一、问题背景
在开发退款记录查询接口时,需要根据退款主表的 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
);