目录
- 一、背景
- 二、单个参数
- 三、多个参数(官方不推荐)
- 四、多个参数(注解方式)
- 五、使用Map参数(不推荐)
- 六、JavaBean对象(推荐)
- 七、使用List参数
- 结语
一、背景
MyBatis 参数的传递,如果对于MyBatis基本使用不了解的可以参考我上一篇文章:MyBatis笔记(一)Spring Boot整合MyBatis实现增删查改详解(入门版).
二、单个参数
单个参数就很简单了,EmployeeMapper.java接口定义如下:
/**
* 根据id获取员工
*/
EmployeeDto getById(String id);
那么EmployeeMapper.xml里对应的配置如下:
<select id="getById" parameterType="string" resultType="EmployeeDto">
SELECT
e.id,
e.emp_name as name,
e.age,
e.salary,
e.department,
e.hire_date as hireDate
FROM
tb_inf_employee e
WHERE
e.id= #{id}
</select>
- 确保 namespace 配置正确和 select 标签的 id 值和接口定义的方法名一致
- select语句后的字段列表要和EmployeeDto中的属性名一致, 如果不一致的可以使用 as 来补充
- 只有一个参数时,#{}中的参数名与Mapper接口方法中的参数名不一样也是可以的,如果想保证一致就在方法定义时,加上 @Param(“id”) ,如下:
/**
* 根据id获取员工
*/
EmployeeDto getById(@Param("id") String id);
三、多个参数(官方不推荐)
当有多个参数时,如果EmployeeMapper.java接口定义如下:
/**
* 根据部门和年龄查找员工
*/
List<EmployeeDto> getByDepartmentAndAgeGreaterThan(String department, int age);
那么EmployeeMapper.xml里对应的配置如下:
<!--查询department部门年龄大于age员工信息-->
<select id="getByDepartmentAndAgeGreaterThan" resultType="EmployeeDto">
SELECT
e.id,
e.emp_name as name,
e.age,
e.salary,
e.department,
e.hire_date as hireDate
FROM
tb_inf_employee e
WHERE
e.department= #{0} and age ">> #{1}
</select>
- 确保 namespace 配置正确和 select 标签的 id 值和接口定义的方法名一致
- select语句后的字段列表要和EmployeeDto中的属性名一致, 如果不一致的可以使用 as 来补充
- 这种情况下的多参数就不需要写parameterType参数
- 改用#{index}是第几个就用第几个的索引,索引从0开始
- 大于号(>)需要进行转义为 >
3.4.2版本之后的,总是报错
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException:
Parameter '0' not found. Available parameters are [department, param1, age, param2]
3.4.2版本之后,在org.apache.ibatis.session.Configuration类里的一个参数useActualParamName 从原来的false改成了true。使用#{0}、#{1}等条件代码的可读性不高,转而推荐使用@Param注解声明变量名称,也就是我接下里的一种传参方法。当然我们还是能用,怎么用呢?不要去项目的配置文件application.yml里添加,最优解就是在mybatis.xml的配置文件中增加一个setting:
mybatis.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING-->
<!--如果希望输出sql相关信息就配置logImpl,设置值为STDOUT_LOGGING-->
<setting name="logImpl" value="STDOUT_LOGGING" />
<setting name="cacheEnabled" value="false" />
<setting name="lazyLoadingEnabled" value="false" />
<!--使用驼峰命名方式-->
<setting name="mapUnderscoreToCamelCase" value="true" />
<setting name="callSettersOnNulls" value="true" />
<!--可以使用{index}获取到参数,index下标从0开始-->
<setting name="useActualParamName" value="false"/>
</settings>
</configuration>
四、多个参数(注解方式)
#{index} 的方式,但是官方明显不是很推荐,EmployeeMapper.java接口定义如下:
/**
* 根据部门和姓名查找员工
*/
List<EmployeeDto> getByDepartmentAndNameLike(@Param("department") String department, @Param("name") String name);
那么EmployeeMapper.xml里对应的配置如下:
<!--查询department部门姓名以name开头的员工信息-->
<select id="getByDepartmentAndNameLike" resultType="EmployeeDto">
SELECT
e.id,
e.emp_name as name,
e.age,
e.salary,
e.department,
e.hire_date as hireDate
FROM
tb_inf_employee e
WHERE
e.department= #{department} and e.emp_name like CONCAT(#{name},'%')
</select>
- 确保 namespace 配置正确和 select 标签的 id 值和接口定义的方法名一致
- select语句后的字段列表要和EmployeeDto中的属性名一致, 如果不一致的可以使用 as 来补充
- 这种情况下的多参数就不需要写parameterType参数
- 接口定义的时候增加注解 @Param(“value”),这个注解是 org.apache.ibatis.annotations.Param,相当于给参数弄了一个别名
- 实际引用参数就是 #{value} 这个 value就是 @Param(“value”)里的 value
五、使用Map参数(不推荐)
上面说到当有多个参数时,也可以使用Map来封装传递,EmployeeMapper.java接口定义如下:
/**
* 根据部门和工资查找员工
*/
List<EmployeeDto> getByDepartmentAndSalaryLessThan(Map<String,Object> map);
那么EmployeeMapper.xml里对应的配置如下:
<!--查询department部门工资少于salary的员工信息-->
<select id="getByDepartmentAndSalaryLessThan" parameterType="map" resultType="EmployeeDto">
SELECT
e.id,
e.emp_name as name,
e.age,
e.salary,
e.department,
e.hire_date as hireDate
FROM
tb_inf_employee e
WHERE
e.department= #{department} and e.salary < #{salary}
</select>
- 确保 namespace 配置正确和 select 标签的 id 值和接口定义的方法名一致
- select语句后的字段列表要和EmployeeDto中的属性名一致, 如果不一致的可以使用 as 来补充
- parameterType 的值可以指定为 map,这个map实际就是 java.util.Map
- 小于号(<)需要转义为 <
- 实际引用参数时 #{value}中 value 就是map中 key的名称
六、JavaBean对象(推荐)
我们定义一个查询的bean
package com.alian.mybatisparams.dto;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDate;
@Data
public class QueryDto implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 部门
*/
private String department;
/**
* 开始时间
*/
private LocalDate startDate;
/**
* 结束时间
*/
private LocalDate endDate;
}
上面说到当有多个参数时,也可以使用Map来封装传递,但是参数过多,导致了业务可读性的丧失,导致后续扩展和维护的困难,一般不建议使用,现在我们采用JavaBean方法,EmployeeMapper.java接口定义如下:
/**
* 根据部门一段时间内的入职员工
*/
List<EmployeeDto> getByDepartmentAndHireDateBetween(QueryDto queryDto);
那么EmployeeMapper.xml里对应的配置如下:
<!--查询department部门某段时间入职的员工信息-->
<select id="getByDepartmentAndHireDateBetween" parameterType="QueryDto" resultType="EmployeeDto">
SELECT
e.id,
e.emp_name as name,
e.age,
e.salary,
e.department,
e.hire_date as hireDate
FROM
tb_inf_employee e
WHERE
e.department= #{department} and e.hire_date between #{startDate} and #{endDate}
</select>
- 确保 namespace 配置正确和 select 标签的 id 值和接口定义的方法名一致
- select语句后的字段列表要和EmployeeDto中的属性名一致, 如果不一致的可以使用 as 来补充
- parameterType 指定为我们传入的别名,因为指定了别名的路径( type-aliases-package ),所以这里可以省略完整路径
- 本文这里实际引用值就是取对象(QueryDto)的的属性即可,如果方法定义上加了 @Param(“queryDto”) ,那么使用就要改成 #{queryDto.属性}
七、使用List参数
使用list传入参数,一般用于in操作的比较多,EmployeeMapper.java接口定义如下:
/**
* 根据id列表查询员工
*/
List<EmployeeDto> getByIdIn(@Param("idList") List<String> idList);
那么EmployeeMapper.xml里对应的配置如下:
<!--根据id列表查询员工信息-->
<select id="getByIdIn" resultType="EmployeeDto">
SELECT
e.id,
e.emp_name as name,
e.age,
e.salary,
e.department,
e.hire_date as hireDate
FROM
tb_inf_employee e
WHERE
e.id IN
<foreach collection="idList" item="item" index="index" open="(" separator="," close=")">
#{item}
</foreach>
</select>
- 确保 namespace 配置正确和 select 标签的 id 值和接口定义的方法名一致
- select语句后的字段列表要和EmployeeDto中的属性名一致, 如果不一致的可以使用 as 来补充
- foreach 标签里的 collection 默认的值是 list ,如果你要像我这样使用idList,那么就得在接口中使用 @Param(“idList”)
结语
本文介绍了多种传递参数的方法,我这里只是一个简单类型,实际还可以是复杂的类型,但是用法都是一样的,现在对各种方法进行简单的总结
- 单个参数 #{value} 要保证名称一致就加上 @Param(“value”)
- 多个参数时,使用 #{下标} 方式官方也不是很推荐,希望用 @Param
- 多个参数时,参数个数小于等于5个,建议使用 @Param
- 多个参数时,参数个数大于5时,建议使用用 Java Bean 更好,或者是组合的方式
- map传参看起来是万能的,但是丧失了业务可读性,不是很推荐
- List参数的解析建议加上 @Param(“value”) ,当有多个list时,可读性会更好