前面我们学习了使用动态 SQL 的 if、where、trim元素来处理一些简单查询操作,但对于一些 SQL 语句中含有 in 条件,需要迭代条件集合来生成的情况,我们就需要使用 foreach 标签来实现 SQL 条件的迭代。

MyBatis 中 foreach 迭代

  foreach 主要用在构建 in 条件中,它可以在 SQL 语句中迭代一个集合。它的属性主要有:item、index、collection、 separator、close、open。

  foreach 的基本属性

    对于 SQL 条件循环(in 语句),需要使用 foreach 标签。

    item:表示集合中每一个元素进行迭代时的别名。

    index:指定一个名称,用于表示在迭代过程中,每次迭代到的位置。(可省略)

    open:表示该语句以什么开始(既然是 in 条件语句,所以必然是以 "(" 开始)。

    separator:表示在每次进行迭代之间以什么符号作为分隔符(既然是 in 条件语句,所以必然是以 "," 作为分隔符)。

    close:表示该语句以什么结束(既然是 in 条件语句,所以必然是以 ")" 结束)。

    collection:最关键并最容易出错的属性,需格外注意,该属性必须指定,不同情况下,该属性的值是不一样的。 主要有以下三种情况:

        ◆ 若入参为单参数且参数类型是一个 List 的时候,collection 属性值为 list。

        ◆ 若入参为单参数且参数类型是一个数组的时候, collection 属性值为 array。

        ◆ 若传入参数为多参数,就需要把它们封装为一个 Map 进行处理,collection 属性值为 map 中相应的 key。

MyBatis 入参为数组类型的 foreach 迭代

  案例:根据指定角色列表来获取该角色列表下用户信息列表

   /**
* 根据指定角色列表来获取该角色列表下用户信息列表-foreach_array
* @param roleIds 角色列表
* @return
*/
public List<User> getUserListByRoleIds_foreach_array(Integer[] roleIds);    <!-- 根据指定角色列表来获取该角色列表下用户信息列表-foreach_array -->
<select id="getUserListByRoleIds_foreach_array" resultMap="userListByRoleIds">
SELECT * FROM `smbms_user` WHERE userRole IN
<foreach collection="array" item="roleIds" open="(" separator="," close=")">
#{roleIds} <!-- #{item 属性别名} -->
</foreach>
</select> <resultMap type="user" id="userListByRoleIds">
<id property="id" column="id" />
<result property="userCode" column="userCode" />
<result property="userName" column="userName" />
</resultMap>   @Test // 测试根据指定角色列表来获取该角色列表下用户信息列表-foreach_array
public void testGetUserListByRoleIds_foreach_array() {
SqlSession session = null;
List<User> userList = new ArrayList<User>();
Integer[] roleIds = { 2, 3 };
try {
session = MyBatisUtil.getSqlSession();
userList = session.getMapper(UserMapper.class).getUserListByRoleIds_foreach_array(roleIds);
} catch (Exception e) {
e.printStackTrace();
} finally {
MyBatisUtil.close(session); //关闭sqlSession
} System.out.println("userList.size--->" + userList.size());
for (User user : userList) {
System.out.println("user ====>" + "userCode:" + user.getUserCode() + ",userName:" + user.getUserName());
}
}

  说明:在上述示例中,我们发现 UserMapper.xml 中的 SELECT:getUserListByRoleIds_foreach_array 中并没有指定 parameterType,这样也是没有问题的。因为配置文件中的 parameterType 是可以不配置的,MyBatis 会自动把它封装成一个 Map 进行传入,但是也需要注意:若入参为 Collection 时,不能直接传入 Collection 对象,需要先将其转换为 LIST 或者数组才能传入,具体原因可参看 MyBatis 源码。

MyBatis 入参为 List 类型的 foreach 迭代

  修改上面的示例,将参数类型改为传入一个 List 实例来实现同样需求。

   /**
* 根据指定角色列表来获取该角色列表下用户信息列表-foreach_list
* @param roleIds 角色列表
* @return
*/
public List<User> getUserListByRoleIds_foreach_list(List<Integer> roleList);    <!-- 根据指定角色列表来获取该角色列表下用户信息列表-foreach_list -->
<select id="getUserListByRoleIds_foreach_list" resultMap="userListByRoleIds">
SELECT * FROM `smbms_user` WHERE userRole IN
<foreach collection="list" item="roleList" open="(" separator="," close=")">
#{roleList} <!-- #{item 属性别名} -->
</foreach>
</select> <resultMap type="user" id="userListByRoleIds">
<id property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>
</resultMap> @Test // 测试根据指定角色列表来获取该角色列表下用户信息列表-foreach_list
public void testGetUserListByRoleIds_foreach_list() {
SqlSession session = null;
List<User> userList = new ArrayList<User>();
List<Integer> roleList=new ArrayList<Integer>();
roleList.add(2);
roleList.add(3);
try {
session = MyBatisUtil.getSqlSession();
userList = session.getMapper(UserMapper.class).getUserListByRoleIds_foreach_list(roleList);
} catch (Exception e) {
e.printStackTrace();
} finally {
MyBatisUtil.close(session); //关闭sqlSession
} System.out.println("userList.size--->" + userList.size());
for (User user : userList) {
System.out.println("user ====>" + "userCode:" + user.getUserCode() + ",userName:" + user.getUserName());
}
}

  注意:foreach 元素非常强大,允许我们指定一个集合,并指定开始和结束的字符,也可加入一个分隔符到迭代器中,并能够智能处理该分膈符,不会出现多余的分隔符。

MyBatis 入参为 Map 类型的 foreach 迭代

  在以上两个示例中,MyBatis 入参均为一个参数,若多个参数入参该如何处理?比如说在上一示例中需求更改为增加一个参数 gender ,要求查询出指定性别和用户角色列表下的所有用户信息列表。

    除了使用 @Param 注解,若入参为多个参数,还可以把它们封装为一个 Map 进行处理。此处我们就采用这种处理方式来解决此需求。

 

  案例查询出指定性别和用户角色列表下的所有用户信息列表/**     * 根据用户角色列表和性别(多参数),获取该角色列表下指定性别的用户列表信息-foreach_map

     * @param conditionMap 角色列表和性别封装的 map 对象
* @return
*/
public List<User> getUserListByConditionMap_foreach_map(Map<String, Object> conditionMap); <!--根据用户角色列表和性别(多参数),获取该角色列表下指定性别的用户列表信息-foreach_map-->
<select id="getUserListByConditionMap_foreach_map" resultMap="userMapByRole">
SELECT * FROM `smbms_user` WHERE gender=#{gender} AND userRole IN
<foreach collection="roleIds" item="roleMap" open="(" separator="," close=")">
#{roleMap} <!-- #{item 属性别名},collection="roleIds" Map 中相应的 key -->
</foreach>
</select> <resultMap type="user" id="userMapByRole">
<id property="id" column="id" />
<result property="userCode" column="userCode" />
<result property="userName" column="userName" />
</resultMap>   @Test // 测试根据用户角色列表和性别(多参数),获取该角色列表下指定性别的用户列表信息-foreach_map
public void testGetUserListByConditionMap_foreach_map() {
SqlSession session = null;
List<User> userList = new ArrayList<User>(); List<Integer> roleList=new ArrayList<Integer>();
roleList.add(2);
roleList.add(3); Map<String, Object> conditionMap=new HashMap<String, Object>();
conditionMap.put("gender", 1);
conditionMap.put("roleIds", roleList);
try {
session = MyBatisUtil.getSqlSession();
userList = session.getMapper(UserMapper.class).getUserListByConditionMap_foreach_map(conditionMap);
} catch (Exception e) {
e.printStackTrace();
} finally {
MyBatisUtil.close(session); //关闭sqlSession
} System.out.println("userList.size--->" + userList.size());
for (User user : userList) {
System.out.println("user ====>" + "userCode:" + user.getUserCode() + ",userName:" + user.getUserName());
}
} 说明:Map 作为入参,SQL 语句中需根据 key 分别获得相应的 value 值。如:collection="roleIds" --->conditionMap.put("roleIds", roleList) 和 gender=#{gender}--->conditionMap.put("gender", 1);
 

使用 Map 封装单参数入参

  单参数也可以封装 Map,使用 Map 进行方法入参,我们可以自由指定 Map 的 key。实际上,MyBatis 在进行参数入参的时候,都会把它封装成一个 Map,而 Map 的 key 就是参数名,对应的参数值就是 Map 的 value。若参数为集合的时候,Map 的 key 会根据传入的是 List 还是数组对象相应地指定为 "list" 或者 "array"。

  案例修改使用数组和List 作为参数的示例,根据指定角色列表来获取用户信息列表,使用 Map 封装单参数入参 

    /**
* 根据用户角色列表,获取该角色列表下用户列表信息-foreach_map(单参数封装成 map)
* @param roleMap 由用户角色 id 列表封装的 map 对象
* @return
*/
public List<User> getUserListByRoleIds_foreach_map(Map<String, Object> roleMap); <!-- 根据用户角色列表,获取该角色列表下用户列表信息-foreach_map(单参数封装成 map) -->
<select id="getUserListByRoleIds_foreach_map" resultMap="userMapByRoleIds">
SELECT * FROM `smbms_user` WHERE userRole IN
<foreach collection="rKey" item="roleMap" open="(" separator="," close=")">
#{roleMap}
</foreach>
</select> <resultMap type="user" id="userMapByRoleIds">
<id property="id" column="id" />
<result property="userCode" column="userCode" />
<result property="userName" column="userName" />
</resultMap> @Test //测试根据用户角色列表,获取该角色列表下用户列表信息-foreach_map(单参数封装成 map)
public void testGetUserListByRoleIds_foreach_map() {
SqlSession session = null;
List<User> userList = new ArrayList<User>(); List<Integer> roleList = new ArrayList<Integer>();
roleList.add(2);
roleList.add(3); Map<String, Object> roleMap=new HashMap<String, Object>();
roleMap.put("rKey", roleList);
try {
session = MyBatisUtil.getSqlSession();
userList = session.getMapper(UserMapper.class).getUserListByRoleIds_foreach_map(roleMap);
} catch (Exception e) {
e.printStackTrace();
} finally {
MyBatisUtil.close(session); // 关闭sqlSession
} System.out.println("userList.size--->" + userList.size());
for (User user : userList) {
System.out.println("user ====>" + "userCode:" + user.getUserCode() + ",userName:" + user.getUserName());
}
}

choose(when、otherwise)

  对于某些查询需求,虽有多个查询条件,但是我们不想应用所有的条件,只想选择其中一种情况下的查询结果。其实和 Java 中 switch 语句相似,MyBatis 提供 choose 元素来满足这种需求。
choose 元素的作用相当于 Java 中的 switch 语句,基本上跟 JSTL 中 choose 的作用和用法是一样的,通常都是搭配 when,otherwise 使用。
    choose(when、otherwise)语法讲解
<choose>
<when test="条件1"></when>
<when test="条件2"></when>
<when test="条件3"></when>
......
<otherwise>...</otherwise>
</choose> 说明:
1、choose 一般与 when、otherwise配套使用。
2、when 元素:当其 test 属性中条件满足的时候,就会输出 when 元素中的内容。跟 Java 中的 switch 效果差不多的是同样按照条件顺序来进行处理,
并当 when 中一旦有条件满足的时候,就会跳出 choose,即所有的 when和 otherwise 条件中,只有一个条件会输出。
3、otherwise 元素:当 when 中所有条件都不满足的时候,就会自动输出 otherwise 元素中的内容。
4、处理多余的 and ,可在 where 后加上 1=1 。

 
案例:
根据条件(用户名称、用户角色、用户编码、创建时间)查询用户表。
     要求:查询条件提供前三个(用户名称、用户角色、用户编码)中的任意一个即可,若前三个条件都不提供,那么默认提供最后一个条件(创建时间:在指定的年份内)来完成查询操作。
    /**
* 根据条件(用户名称、用户角色、用户编码、创建时间)查询用户表(choose用法)
* @param userName 用户名称
* @param roleId 用户角色 id
* @param userCode 用户编码
* @param creationDate 创建时间
* @return
*/
public List<User> getUserList_choose(@Param("userName")String userName,
@Param("userRole")Integer roleId,
@Param("userCode")String userCode,
@Param("creationDate")Date creationDate); <!--根据条件(用户名称、用户角色、用户编码、创建时间)查询用户表(choose用法) -->
<select id="getUserList_choose" resultType="user">
select * from smbms_user where 1=1
<choose>
<when test="userName != null and userName != ''">
and userName like CONCAT ('%',#{userName},'%')
</when>
<when test="userCode != null and userCode != ''">
and userCode like CONCAT ('%',#{userCode},'%')
</when>
<when test="userRole != null">
and userRole=#{userRole}
</when>
<otherwise>
<!-- and YEAR(creationDate) = YEAR(NOW()) -->
and YEAR(creationDate) = YEAR(#{creationDate})
</otherwise>
</choose>
</select> @Test // 测试根据条件(用户名称、用户角色、用户编码、创建时间)查询用户表(choose用法)
public void testGetUserList_choose() {
SqlSession session = null;
List<User> userList = new ArrayList<User>();
try {
session = MyBatisUtil.getSqlSession();
String userName = "";
Integer roleId = null;
String userCode = "";
Date creationDate = new SimpleDateFormat("yyyy-MM-dd").parse("2016-01-01");
userList = session.getMapper(UserMapper.class).getUserList_choose(userName, roleId, userCode, creationDate);
} catch (Exception e) {
e.printStackTrace();
} finally {
MyBatisUtil.close(session); // 关闭sqlSession
}
System.out.println("userlist.size ----> " + userList.size());
for (User user : userList) {
System.out.println("testGetUserList_choose=======> id: " + user.getId() + " and userCode: "
+ user.getUserCode() + " and userName: " + user.getUserName() + " and userRole: "
+ user.getUserRole() + " and creationDate: "
+ new SimpleDateFormat("yyyy-MM-dd").format(user.getCreationDate()));
}
}
 

动态 SQL(2)的更多相关文章

  1. 值得注意的ibatis动态sql语法格式

    一.Ibatis常用动态sql语法,简单粗暴用一例子 <select id="iBatisSelectList" parameterClass="java.util ...

  2. Mysql - 游标/动态sql/事务

    游标这个在我目前的项目里面用的还不多, 但是其功能还是很强大的. 动态sql以前都没用过, 是跟着富士康(不是张全蛋的富土康哦)过来的同事学的. 还是挺好用的. 我的数据库方面, 跟他学了不少. 在此 ...

  3. MyBatis4:动态SQL

    什么是动态SQL MyBatis的一个强大特性之一通常是它的动态SQL能力.如果你有使用JDBC或其他相似框架的经验,你就明白条件串联SQL字符串在一起是多么地痛苦,确保不能忘了空格或者在列表的最后的 ...

  4. 分享公司DAO层动态SQL的一些封装

    主题 公司在DAO层使用的框架是Spring Data JPA,这个框架很好用,基本不需要自己写SQL或者HQL就能完成大部分事情,但是偶尔有一些复杂的查询还是需要自己手写原生的Native SQL或 ...

  5. MySQL存储过程动态SQL语句的生成

    用Mysql存储过程来完成动态SQL语句,使用存储过程有很好的执行效率: 现在有要求如下:根据输入的年份.国家.节假日类型查询一个节假日,我们可以使用一般的SQL语句嵌入到Java代码中,但是执行效率 ...

  6. 【Java EE 学习 79 下】【动态SQL】【mybatis和spring的整合】

    一.动态SQL 什么是动态SQL,就是在不同的条件下,sql语句不相同的意思,曾经在“酒店会员管理系统”中写过大量的多条件查询,那是在SSH的环境中,所以只能在代码中进行判断,以下是其中一个多条件查询 ...

  7. 自定义函数执行动态sql语句

    --函数中不能调用动态SQL,使用用存储过程吧.如果还要对函数做其他操作,换成存储过程不方便,可以考虑把其他操作一起封装在存储过程里面.如:   create proc [dbo].[FUN_YSCL ...

  8. mybatis入门基础(五)----动态SQL

    一:动态SQL 1.1.定义 mybatis核心对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接.组装. 1.2.案例需求 用户信息综合查询列表这个statement的定义使用动态s ...

  9. mybatis 动态sql表达式相关应用

    一.mybatis 表达式简介 对于mybatis3 ,提供了一种动态sql的方式.通过动态sql我们可以直接在mybatis 的xm映射文件中直接通过条件判断的方式进行查询添加的拼接.mybatis ...

  10. (转)Mybatis高级映射、动态SQL及获得自增主键

    原文:http://www.cnblogs.com/edwinchen/p/4105278.html?utm_source=tuicool&utm_medium=referral 一.动态SQ ...

随机推荐

  1. NSubstitute

    https://github.com/nsubstitute/NSubstitute http://nsubstitute.github.io/help/creating-a-substitute/

  2. DTV_SI 汇总 & 兼谈LCN

    前言 本章主要对数字广播DVB做一个系统的概况的描述,以及一些spc的相关的内容,虽然流程分析的不多,但是做为后续 章节资料的源泉,也是不可或缺的. 一. ATSC和DVB数字电视系统的比较 本文的主 ...

  3. Could not find modernizr-2.6.2 in any of the sources

  4. 昆石VOS3000_2.1.2.4完整安装包及安装脚本

    安装包下载地址:http://www.51voip.org/post/56.html 安装教程: 上传安装包 ·给整个目录授权 chmod 777 /root/vosintsall `核实 关闭sel ...

  5. 搜索goog

    http://www.tech365.net/share/24.html 64.233.160.132|64.233.168.17|64.233.168.167|64.233.160.98|64.23 ...

  6. Android 在eclipse中没有出现AVD的解决方法(转载)

    转自:http://frabbit2013.blog.51cto.com/1067958/1243549 本文主要介绍在系统中成功配置好Android开发环境(即SDK is ok and ADT o ...

  7. .gitignore(转载)

    转自:http://blog.csdn.net/liuqiaoyu080512/article/details/8648266 git 可以管理所有文件的变更, 但并不是所有文件都有意义. 大部分二进 ...

  8. bzoj 1047: [HAOI2007]理想的正方形【单调队列】

    没有复杂结构甚至不长但是写起来就很想死的代码类型 原理非常简单,就是用先用单调队列处理出mn1[i][j]表示i行的j到j+k-1列的最小值,mx1[i][j]表示i行的j到j+k-1列的最大值 然后 ...

  9. P3990 [SHOI2013]超级跳马

    传送门 首先不难设\(f[i][j]\)表示跳到\((i,j)\)的方案数,那么不难得到如下转移 \[f[i][j]=\sum\limits_{k=1}^{\frac n2}f[i-2k+1][j-1 ...

  10. [App Store Connect帮助]三、管理 App 和版本(6.3)转让 App:接受 App 转让

    您必须在转让发起的 60 天内接受转让. 必要职能:“帐户持有人”职能.请参见职能权限. 以具有“帐户持有人”职能用户的身份登录至 App Store Connect. 系统会显示一条通知,指示 Ap ...