MyBatis笔记(二)MyBatis参数传递详解

一、背景

  本文的主要介绍 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 &gt; #{1}
  	</select>
  • 确保 namespace 配置正确和 select 标签的 id 值和接口定义的方法名一致
  • select语句后的字段列表要和EmployeeDto中的属性名一致, 如果不一致的可以使用 as 来补充
  • 这种情况下的多参数就不需要写parameterType参数
  • 改用#{index}是第几个就用第几个的索引,索引从0开始
  • 大于号(>)需要进行转义为 &gt; ,当然我这个最新版不转义也是可以的

  实际上使用的时候你会觉得我忽悠你,尤其是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 &lt; #{salary}
  	</select>
  • 确保 namespace 配置正确和 select 标签的 id 值和接口定义的方法名一致
  • select语句后的字段列表要和EmployeeDto中的属性名一致, 如果不一致的可以使用 as 来补充
  • parameterType 的值可以指定为 map,这个map实际就是 java.util.Map
  • 小于号(<)需要转义为 &lt; 当然我这个最新版不转义也是可以的
  • 实际引用参数时 #{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时,可读性会更好
  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值