四、Mybatis多id查询之foreach标签的使用

当传入的参数是一个集合,我们需要遍历取出集合中的每一个参数时,就需要用到foreach标签了,这里介绍它的6个常用属性:

  • collection:指传入可迭代(遍历)的参数的变量名称。
    • 当传入的参数为list类型,为list
    • 当传入的参数为array类型,为array
    • 当传入的参数为map类型,为map的键key(较少使用)
    • 当传入的参数是java bean类型,那么保持和该java bean对象中支持遍历的属性的名称一致
  • item:迭代集合时,元素的别名
  • index:在list和数组中,index是元素的序号,在map中,index是元素的key
  • open:循环开始拼接的字符串
  • close:循环结束拼接的字符串
  • separator:循环中拼接的分隔符

其中collection和item参数为必填!

举个例子,多个id查询的sql语句可以写成这样

select * from user  where id in (1,2,3,4)

上面的语句表示查询id为1,2,3,4的数据,那么如果在mybatis的映射文件该如何书写呢,我们总不可能直接写死这些id吧?

<select>标签的parameterType属性,我们可以指定参数类型为java.util.List,表示输入参数是一个list集合,显然我是想将所有需要查询的id保存到这个list集合中。

然后UserMapper.xml中的<select>标签体内的sql语句就可以这样书写了:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- mapper接口代理实现规则: 
	1.映射文件中namespace要等于接口的全路径名称 
	2. 映射文件中sql语句的id要等于接口的方法名称 
	3. 映射文件中传入参数类型要等于接口方法的传入参数类型 
	4. 映射文件中返回结果集类型要等于接口方法的返回值类型,如果接口方法的返回值类型是集合,那么它表示的就是集合中的泛型参数类型 -->
<mapper namespace="blog.csdn.net.mchenys.mapper.UserMapper">

	
	<select id="findUserByIds" parameterType="java.util.List" 
		resultType="blog.csdn.net.mchenys.poj.User">
		
		select * from user 
		<where>
			<if test="list != null">
				<!-- 循环传入的集合参数
					 collection:传入参数中的集合的变量名称
					 item:每次循环从集合中取出的数据保存到item中
					 open:循环开始拼接的字符串
					 close:循环结束拼接的字符串
					 separator:循环中拼接的分隔符
				 -->
				<foreach collection="list" item="id" open="id in(" close=")" separator=",">
					#{id}
				</foreach>
			</if>
		</where>
	</select>

</mapper>

对于的UserMapper接口方法如下:

public List<User> findUserByIds(List<Integer> list);

由于select标签的parameterType属性传入的参数是List集合,所以foreach 标签的collection属性的变量名就是小写的list。

在UserMapperTest测试类中添加测试方法进行测试:

// 同时查询多个id
@Test
public void testFindUserByIds() throws Exception {
	SqlSession session = factory.openSession();
	UserMapper mapper = session.getMapper(UserMapper.class);

	List<Integer> ids = new ArrayList<Integer>();
	ids.add(33);
	ids.add(34);
	ids.add(35);
	ids.add(36);

	List<User> list = mapper.findUserByIds(ids);

	System.out.println(list);
}

控制台输出的结果:
在这里插入图片描述
假设我把foreach标签的collection属性值改成ids,再次运行就会看到这个错误:
在这里插入图片描述
意思就是找不到ids,可用的参数叫list。

封装传入参数

虽然parameterType的值可以直接指定具体的参数类型,但是还是建议将需要用到的参数封装到一个实体bean中,然后再把该实体bean当做输入参数来用。

还是以上面那个例子为例,我将List集合封装到一个java bean类中,例如:

public class QueryVo {
	
	private List<Integer> ids;

	public void setIds(List<Integer> ids) {
		this.ids = ids;
	}

	public List<Integer> getIds() {
		return ids;
	}
}

然后映射文件修改如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- mapper接口代理实现规则: 
	1.映射文件中namespace要等于接口的全路径名称 
	2. 映射文件中sql语句的id要等于接口的方法名称 
	3. 映射文件中传入参数类型要等于接口方法的传入参数类型 
	4. 映射文件中返回结果集类型要等于接口方法的返回值类型,如果接口方法的返回值类型是集合,那么它表示的就是集合中的泛型参数类型 -->
<mapper namespace="blog.csdn.net.mchenys.mapper.UserMapper">

	
	<select id="findUserByIds2" parameterType="blog.csdn.net.mchenys.poj.QueryVo" 
		resultType="blog.csdn.net.mchenys.poj.User">
		
		select * from user 
		<where>
			<if test="ids != null">
				<!-- 循环传入的集合参数
					 collection:传入的集合变量名称
					 item:每次循环从集合中取出的数据保存到item中指定的变量名
					 open:循环开始拼接的字符串
					 close:循环结束拼接的字符串
					 separator:循环中拼接的分隔符
				 -->
				<foreach collection="ids" item="id" open="id in(" close=")" separator=",">
					#{id}
				</foreach>
			</if>
		</where>
	</select>

</mapper>

对应的UserMapper接口添加一个findUserByIds2的方法

public List<User> findUserByIds2(QueryVo vo);

注意上面映射文件中foreach 标签的collection属性值变成了ids,因为QueryVo 类中的集合属性就是ids,这2个名字是必须对应的,否则会报错,稍后会演示该错误。

在UserMapperTest测试类中添加测试方法进行测试:

// 同时查询多个id
@Test
public void testFindUserByIds2() throws Exception {
	SqlSession session = factory.openSession();
	UserMapper mapper = session.getMapper(UserMapper.class);

	QueryVo queryVo = new QueryVo();
	List<Integer> ids = new ArrayList<Integer>();
	ids.add(10);
	ids.add(16);
	ids.add(22);
	ids.add(24);
	queryVo.setIds(ids);

	List<User> list = mapper.findUserByIds2(queryVo);

	System.out.println(list);
}

控制台输出的结果:
在这里插入图片描述
效果和直接传List集合的一样,但是封装后,灵活度大一点,因为我们可以将同一个业务的各种sql语句的传入参数都封装到一个java bean中进行维护。

上面提到过,如果映射文件中foreach标签的collection属性值和java bean中的集合属性名称不一样会报错,例如我将collection的属性值 ids 改成 ids2,再次运行测试代码就会看到这个错误:
在这里插入图片描述
意思就是在QueryVo实体类中找不到有叫ids2的属性,注意java bean规范中有getter方法的字段才能叫属性,看上图的异常也能说明这点,mybatis会去java bean中查找符合条件的getter方法,然后截取get后的方法名首字母小写就是对应的属性名,当然getter方法不是必须的,mybatis会根据collection属性值去java bean中优先找符合条件的字段名,如果找不到才会去找对应的getter方法名。

例如collection中的属性值是ids, 然后QueryVo实体类中的字段存在ids且类型是List集合类型,那么mybatis就能与之对应,无需提供getIds方法,用代码来表示就是这样的:

public class QueryVo {
	
	private List<Integer> ids;//字段名是ids,且类型是List集合就符合条件了

	public void setIds(List<Integer> ids) {
		this.ids = ids;
	}
	
	//没有提供getIds方法也ok
	
}

同理,假设QueryVo实体类中ids字段的类型不是List,但是有个叫getIds的方法,且返回值是List集合类型,那么mybatis也不会报错,它也能识别,什么意思呢,用代码来表示就是这样的:

public class QueryVo {
	
	private List<Integer> list;
	
	private String ids; //字段符合,但是类型不符合

	public void setIds(List<Integer> ids) {
		this.list = ids;
	}

	public List<Integer> getIds() {  //存在getter方法,且参类型符合也ok
		return list;
	}
}

运行后,一点问题都没有,顺利通过,不过话又说回来,没有人会这么干的,一般都是按照java bean的规范来,都会提供getter方法的。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值