MyBatis 批量插入时 Parameter 'carNum' not found 错误详解
一、错误现象
运行批量插入测试时抛出:
org.apache.ibatis.binding.BindingException: Parameter 'carNum' not found.
Available parameters are [cars, param1]
并且 SQL 显示为:
sql
insert into t_car car_num,brand,guide_price,produce_time,car_type values (?,?,?,?,?) , (?,?,?,?,?)
二、错误含义
这个错误包含两个问题:
- 参数绑定错误 :
Parameter 'carNum' not found--- XML 中使用了#{carNum},但 MyBatis 找不到名为carNum的参数。 - SQL 语法错误 :
insert into t_car car_num,brand,...---INSERT语句中表名后面缺少左括号(。
三、根本原因分析
3.1 问题一:参数绑定错误
查看你的 XML 配置,<foreach> 中很可能写成了:
xml
<foreach collection="cars" item="car" separator=",">
(#{carNum}, #{brand}, #{guidePrice}, #{produceTime}, #{carType})
</foreach>
但是:
- 方法参数使用了
@Param("cars"),类型是List<Car> - 遍历时
item="car"代表集合中的每个Car对象 - 访问对象的属性时,必须加上
item前缀 :#{car.carNum}、#{car.brand}
错误写法 :#{carNum}(MyBatis 会从顶层参数中找名为 carNum 的单独参数,找不到)
正确写法 :#{car.carNum}(从当前遍历的 car 对象中取 carNum 属性)
3.2 问题二:SQL 语法错误
SQL 语句:
sql
insert into t_car car_num,brand,guide_price,produce_time,car_type values ...
应该是:
sql
insert into t_car (car_num, brand, guide_price, produce_time, car_type) values ...
表名 t_car 后面缺少左括号 (。
3.3 从日志看具体问题
日志中显示:
Parameter 'carNum' not found. Available parameters are [cars, param1]
这说明 MyBatis 的可用参数只有两个:cars(@Param 注解名)和 param1(默认名)。当你写 #{carNum} 时,MyBatis 会去查找名为 carNum 的顶层参数,但 carNum 既不是 @Param("cars"),也不是 param1,所以找不到。
同时,生成的 SQL 中字段列表缺少括号,这是 XML 中 INSERT 语句本身的问题。
四、解决方案
4.1 修正后的 XML
xml
<insert id="insertMore">
INSERT INTO t_car (car_num, brand, guide_price, produce_time, car_type)
VALUES
<foreach collection="cars" item="car" separator=",">
(#{car.carNum}, #{car.brand}, #{car.guidePrice},
#{car.produceTime}, #{car.carType})
</foreach>
</insert>
4.2 修正点对比
| 错误写法 | 正确写法 | 说明 |
|---|---|---|
insert into t_car car_num |
INSERT INTO t_car (car_num |
表名后加 ( |
#{carNum} |
#{car.carNum} |
加上 item 前缀 |
#{brand} |
#{car.brand} |
加上 item 前缀 |
#{guidePrice} |
#{car.guidePrice} |
加上 item 前缀 |
#{produceTime} |
#{car.produceTime} |
加上 item 前缀 |
#{carType} |
#{car.carType} |
加上 item 前缀 |
4.3 完整示例
Mapper 接口:
java
public interface CarMapper {
int insertMore(@Param("cars") List<Car> carList);
}
XML 映射:
xml
<insert id="insertMore">
INSERT INTO t_car (car_num, brand, guide_price, produce_time, car_type)
VALUES
<foreach collection="cars" item="car" separator=",">
(#{car.carNum}, #{car.brand}, #{car.guidePrice},
#{car.produceTime}, #{car.carType})
</foreach>
</insert>
测试代码:
java
@Test
public void test6() {
List<Car> carList = Arrays.asList(
new Car("京A11111", "宝马", 30.0, "2024-01-01", "燃油车"),
new Car("京A22222", "奔驰", 45.0, "2024-01-02", "燃油车")
);
carMapper.insertMore(carList);
sqlSession.commit();
}
五、#{} 取值规则详解
在 <foreach> 中,#{} 的取值规则与普通场景不同:
| 写法 | 取值对象 | 说明 |
|---|---|---|
#{carNum} |
顶层参数(Map 的 Key) | 从方法参数中查找 carNum 这个 Key |
#{car.carNum} |
item 对象的属性 |
从当前遍历的 car 对象中取 carNum 属性 |
#{item.carNum} |
同上 | 如果 item="item",写法为 #{item.carNum} |
关键 :在 <foreach> 内部,当 item 是对象时,必须通过 item.属性名 访问属性;当 item 是基本类型时,直接写 #{item} 即可。
六、常见错误速查表
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
Parameter 'xxx' not found. Available parameters are [cars, param1] |
未加 item 前缀 |
改为 #{car.xxx} |
Parameter 'list' not found. Available parameters are [cars, param1] |
collection 值写错 |
改为 collection="cars" |
SQL 语法错误 near 'values (?,?,?)' |
表名后缺少 ( |
加上 (car_num, brand, ...) |
插入成功但数据为 null |
字段名写错 | 检查字段名是否匹配数据库列 |
七、排查步骤总结
遇到批量插入错误时,按以下步骤检查:
- ✅ 检查 SQL 语法是否正确(表名后有
(,VALUES后有() - ✅ 检查
<foreach>的collection是否与@Param一致 - ✅ 检查
item是否在#{}中作为前缀使用(如#{item.xxx}) - ✅ 开启 MyBatis 日志,查看生成的完整 SQL
- ✅ 确认实体类属性名与数据库列名对应关系
结语
批量插入是 MyBatis 中最常见的性能优化手段之一,但也是参数绑定最容易出错的地方。
记住两条核心规则:
collection的名称必须与@Param注解值或默认名称(list/array)一致。#{}中如果要访问对象的属性,必须加上item前缀(如#{car.xxx})。
掌握这两条规则,批量插入的各种错误都能迎刃而解。