前面我们学习了使用动态 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. pandas 绘图 机器学习看特征相关性

    pandas 绘图 import numpy as np import tflearn from tflearn.layers.core import dropout from tflearn.lay ...

  2. 类型配置命名空间 —— XML schema

    对于基于 XML 的配置,Spring 2.0 以后告别 DTD 格式(Document Type Definition)的配置文件,开始采用 Schema 格式,Schema 的突出亮点即是可让不同 ...

  3. bzoj 2067 [ Poi 2004 ] SZN —— 二分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2067 问题1:贪心考虑,应该是每个点的儿子尽量两两配对,如果剩一个就和自己合并向上,所以 a ...

  4. bzoj1791

    1791: [Ioi2008]Island 岛屿 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1680  Solved: 369[Submit][S ...

  5. Excel设定编辑列权限的方法

    工具---保护--允许用户编辑区域 --新建-- 选择(或输入)引用单元格 ,区域密码:对不同的人不同的区域用不同的密码,设置完成后,保护工作表(密码用管理员的),即可

  6. Rails 确认params的统一方法

    创建: 2017/11/06    Gemfile  ### デバッグ出力の整形  gem 'awesome_print', :group => [:development, :test]  a ...

  7. 洛谷P3383 【模板】线性筛素数 (埃拉托斯特尼筛法)

    题目描述 如题,给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内) 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示查询的范围和查询的个数. 接下来M行每行 ...

  8. Linux上安装禅道

    linux一键安装包内置了apache, php, mysql这些应用程序,只需要下载解压缩即可运行禅道. 从7.3版本开始,linux一键安装包分为32位和64位两个包,请大家根据操作系统的情况下载 ...

  9. JavaScript--History 对象

    history对象记录了用户曾经浏览过的页面(URL),并可以实现浏览器前进与后退相似导航的功能. 注意:从窗口被打开的那一刻开始记录,每个浏览器窗口.每个标签页乃至每个框架,都有自己的history ...

  10. [JOI2014] 小笼包

    题面 : https://www.ioi-jp.org/joi/2013/2014-yo/2014-yo-t6/2014-yo-t6.html 题解 dp + 康托展开 一看这题不知道怎么处理 只能枚 ...