MyBatis 多参数绑定错误:Parameter 'name' not found 详解与解决方案
一、错误现象
运行测试时抛出:
sql
org.apache.ibatis.binding.BindingException: Parameter 'name' not found.
Available parameters are [arg1, arg0, param1, param2]
二、错误含义
这是 MyBatis 中最经典的多参数绑定错误。当 Mapper 接口方法有多个参数 ,且未使用 @Param 注解时,MyBatis 会使用默认参数名(arg0、arg1 或 param1、param2),但你的 XML 中却使用了自定义名称(如 #{name}),导致找不到对应的参数。
错误信息中的 Available parameters are [arg1, arg0, param1, param2] 是 MyBatis 给出的提示,告诉你可以使用的参数名有哪些。
三、错误重现
你的测试代码调用了 selectStudentByNameAndSex 方法,根据堆栈信息,你的代码结构可能是这样:
Mapper 接口 (未使用 @Param):
java
public interface StudentMapper {
// ❌ 错误:多参数但未加 @Param
List<Student> selectStudentByNameAndSex(String name, Character sex);
}
XML 映射(使用了自定义参数名):
xml
<select id="selectStudentByNameAndSex" resultType="Student">
SELECT * FROM student
WHERE name = #{name} <!-- 这里用了 #{name},但 MyBatis 找不到这个参数 -->
AND sex = #{sex} <!-- 这里用了 #{sex},也找不到 -->
</select>
执行流程:
- MyBatis 将
name和sex两个参数封装为 Map。 - 因为没有
@Param,Map 的 Key 是默认的arg0/arg1或param1/param2。 - 当解析
#{name}时,MyBatis 去 Map 中查找 Key 为"name"的值,发现不存在。 - 抛出
Parameter 'name' not found异常。
四、解决方案
方案一:使用 @Param 注解(最推荐)
为每个参数添加 @Param 注解,指定参数名称。
修正后的 Mapper 接口:
java
public interface StudentMapper {
// ✅ 正确:使用 @Param 明确指定参数名
List<Student> selectStudentByNameAndSex(@Param("name") String name,
@Param("sex") Character sex);
}
XML 保持不动 ,因为 #{name} 和 #{sex} 现在可以正确映射到 @Param 指定的名称。
方案二:使用默认参数名(不推荐,可读性差)
如果不想加 @Param,可以使用 MyBatis 的默认参数名。
xml
<select id="selectStudentByNameAndSex" resultType="Student">
SELECT * FROM student
WHERE name = #{arg0} <!-- 或 #{param1} -->
AND sex = #{arg1} <!-- 或 #{param2} -->
</select>
不推荐原因:
- 可读性差,无法直观看出参数含义。
- 参数顺序变化时需要同步修改 XML,容易出错。
方案三:使用 Map 传参
将多个参数封装成一个 Map。
java
// Mapper 接口
List<Student> selectStudentByMap(Map<String, Object> params);
xml
<select id="selectStudentByMap" parameterType="map" resultType="Student">
SELECT * FROM student
WHERE name = #{name}
AND sex = #{sex}
</select>
调用时:
java
Map<String, Object> params = new HashMap<>();
params.put("name", "张三");
params.put("sex", 'M');
List<Student> students = studentMapper.selectStudentByMap(params);
五、底层原理
MyBatis 参数解析由 ParamNameResolver 类负责:
- 检查是否有
@Param注解 :- 如果有,以注解的值为 Key。
- 如果没有
@Param注解 :- 使用索引名:
arg0、arg1、arg2...(JDK 8+)或param1、param2、param3...(通用) - 如果只有一个参数,还可以使用
_parameter作为 Key(不是本章重点)。
- 使用索引名:
六、最佳实践总结
| 规则 | 说明 |
|---|---|
多参数必须加 @Param |
这是最清晰、最安全、最易维护的做法 |
即使单参数,也推荐加 @Param |
保持一致性,避免 ${} 场景下的 value 陷阱 |
避免使用 arg0/arg1 |
可读性差,参数顺序变化时容易出错 |
| 参数超过 3 个时,考虑封装为 POJO 或 Map | 减少接口参数数量,提高可读性 |
七、修正后的完整示例
java
public interface StudentMapper {
// ✅ 正确写法:多参数使用 @Param
List<Student> selectStudentByNameAndSex(@Param("name") String name,
@Param("sex") Character sex);
// ✅ 单个参数建议也加 @Param(保持一致性)
List<Student> selectStudentByBirth(@Param("birth") Date birth);
}
xml
<mapper namespace="com.xie.mapper.StudentMapper">
<select id="selectStudentByNameAndSex" resultType="Student">
SELECT * FROM student
WHERE name = #{name}
AND sex = #{sex}
</select>
<select id="selectStudentByBirth" resultType="Student">
SELECT * FROM student
WHERE birth = #{birth}
</select>
</mapper>
调用代码:
java
@Test
public void test2() {
// 使用 @Param 后,直接传入参数即可
List<Student> students = studentMapper.selectStudentByNameAndSex("张三", 'M');
students.forEach(System.out::println);
}
八、总结
| 错误类型 | 原因 | 解决方案 |
|---|---|---|
Parameter 'name' not found |
多参数方法未使用 @Param,XML 中使用了自定义参数名 |
在 Mapper 接口方法的每个参数前加上 @Param("xxx") 注解 |
记住一条黄金法则 :只要方法有多个参数,就必须为每个参数加上 @Param 注解。 这是避免参数绑定问题的最简单、最有效的方法。