一、前言
本人在学习mybatis的过程中遇到的一个让人不爽的bug,在查找了些相关的资料后得以解决,遂记录。
二、报错及解决
mapper
中有一方法:
@Select("select * from emp " +
"where name like concat('%', #{name}, '%') " +
"and gender = #{gender} " +
"and entrydate between #{begin} and #{end} " +
"order by update_time desc")
public List<Emp> list(String name,Short gender, LocalDate begin, LocalDate end);
测试方法:
@Test
public void testList() {
String name = "张";
Short gender = 1; // 假设1代表男性,0代表女性
LocalDate begin = LocalDate.parse("2001-01-01");
LocalDate end = LocalDate.parse("2023-12-31");
List<Emp> empList = empMapper.list(name, gender, begin, end);
// 遍历打印查询结果
for (Emp emp : empList) {
System.out.println(emp);
}
}
报错信息:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'name' not found. Available parameters are [arg3, arg2, arg1, arg0, param3, param4, param1, param2]
说是name参数找不到,靠。
原因:
在 MyBatis 中,当方法参数只有一个
时,会使用基于位置的参数映射。这意味着 MyBatis 会将第一个参数与 SQL 查询语句中的第一个占位符进行匹配,以此类推。
然而,当方法参数超过一个
时,MyBatis 就无法准确地确定每个参数应该映射到 SQL 查询语句中的哪个占位符。
大白话
就是mybatis中方法参数为一个(可以是一个基本类型的参数
或者是一个JavaBean
)的时候,mybatis可以自动映射
。有多个参数
时需要一些措施让他成功映射。
解决方法:
1、使用
@Param
注解为方法参数指定名称:
@Select("select * from emp " +
"where name like concat('%', #{name}, '%') " +
"and gender = #{gender} " +
"and entrydate between #{begin} and #{end} " +
"order by update_time desc")
public List<Emp> list(@Param("name") String name, @Param("gender") Short gender, @Param("begin") LocalDate begin, @Param("end") LocalDate end);
在接口方法中使用 @Param
注解为每个参数指定名称,确保名称与 SQL 查询语句中的占位符名称匹配。
2、将参数包装在一个对象中:
创建一个包含所有查询参数的对象
,例如 EmpQuery,并将该对象作为方法的参数:
@Select("select * from emp " +
"where name like concat('%', #{name}, '%') " +
"and gender = #{gender} " +
"and entrydate between #{begin} and #{end} " +
"order by update_time desc")
public List<Emp> list(EmpQuery query);
其中 EmpQuery 类包括 name
、gender
、begin
和 end
等字段。
三、@Param
1、概述
首先明确这个注解是为SQL语句中参数赋值而服务的。
@Param
的作用就是给参数命名,比如在mapper里面某方法A(int id)
,当添加注解后A(@Param("userId") int id
),也就是说外部想要取出传入的id值,只需要取它的参数名userId就可以了。将参数值传如SQL语句中,通过#{userId}
进行取值给SQL的参数赋值。
2、实例:
实例一:@Param注解基本类型的参数
public User selectUser(@Param("userName") String name,@Param("password") String pwd);
映射到xml中的标签
<select id="selectUser" resultMap="User">
select * from user where user_name = #{userName} and user_password=#{password}
</select>
实例二:@Param注解JavaBean对象
SQL语句通过@Param注解中的别名把对象中的属性取出来然后复制
mapper中的方法:
public List<User> getAllUser(@Param("user") User u);
映射到xml中的标签
<select id="getAllUser" parameterType="com.vo.User" resultMap="userMapper">
select
from user t where 1=1
and t.user_name = #{user.userName}
and t.user_age = #{user.userAge}
</select>
<!-- 不加@Param的话 -->
<select id="getAllUser" parameterType="com.vo.User" resultMap="userMapper">
select
from user t where 1=1
and t.user_name = #{userName}
and t.user_age = #{userAge}
</select>
3、注意点
当使用了@Param注解
来声明参数的时候,SQL语句取值使用#{}
,${}
取值都可以。
当不使用@Param注解
声明参数的时候,必须使用
的是#{}
来取参数。使用${}方式取值会报错。
不使用@Param注
解时,参数只能有一个
,并且是Javabean
。在SQL语句里可以引用JavaBean的属性,而且只能引用JavaBean的属性。
参考文章:【详解】@Param注解的用法