(第4章):MyBatis动态SQL【foreach、bind、OGNL用法】


 4.4 foreach 用法

SQL 语句中有时会使用 IN 关键字,例如 id in (1,2,3。可以使用 ${ids}方式直接获取值,但这种写法不能防止 SQL 注入,想避免 SQL 注入就需要用#{}的方式,这时就要配合使用 foreach 标签来满足需求

foreach 可以对数组、Map 或实现了 Iterable 接口(如 List、Set)的对象进行遍历数组在处理时会转换为 List 对象,因此 foreach 遍历的对象可以分为两大类:Iterable 类型和 Map 类型。这两种类型在遍历循环时情况不一样,这一节会通过 3 个例子来讲解 foreach 的用法

 4.4.1 foreach 实现 in 集合

foreach 实现 in 集合(或数组)是最简单和常用的一种情况,下面介绍如何根据传入的用户 id 集合查询出所有符合条件的用户。首先在 UserMapper 接口中增加如下方法

    /**
     * 根据用户 id 集合查询
     *
     * @param idList
     * @return
     */
    List<SysUser> selectByIdList(List<Long> idList);

UserMapper.xml 中增加如下代码

    <select id="selectByIdList" resultType="SysUser">
        select id,
        user_name userName,
        user_password userPassword,
        user_email userEmail,
        user_info userInfo,
        head_img headImg,
        create_time createTime
        from sys_user
        where id in
        <foreach collection="list" open="(" close=")" separator="," item="id" index="i">
            #{id}
        </foreach>
    </select>

  foreach 包含以下属性

· collection :必填,值为要迭代循环的属性名。这个属性值的情况有很多

· item:变量名,值为从迭代对象中取出的每一个值

· index:索引的属性名,在集合数组情况下值为当前索引值,当迭代循环的对象是 Map 类型时,这个值为 Map 的 key(键值

· open:整个循环内容开头的字符串

· close:整个循环内容结尾的字符串

· separator :每次循环的分隔符

collection 的属性要如何设置呢?来看一下 MyBatis 是如何处理这种类型的参数的

   1.只有一个数组参数或集合参数

以下代码是 DefaultSqlSession 中的方法,也是默认情况下的处理逻辑

MyBatis从入门到精通(第4章):MyBatis动态SQL【foreach、bind、OGNL用法】

当参数类型为集合的时候,默认会转换为 Map 类型,并添加一个 key 为 collection 的值(MyBatis 3.3.0 版本中增加,如果参数类型是 List 集合,那么就继续添加一个 key 为 list 的值(MyBatis 3.2.8 及低版本中只有这一个 key

这样,当 collection= "list"时,就能得到这个集合,并对它进行循环操作

当参数类型为数组的时候,也会转换成 Map 类型,默认的 key 为 array。当采用如下方法使用数组参数时,就需要把 foreach 标签中的 collection 属性值设置为 array

MyBatis从入门到精通(第4章):MyBatis动态SQL【foreach、bind、OGNL用法】

上面提到的是数组或集合类型的参数默认的名字。推荐使用@Param 来指定参数的名字,这时 collection 就设置为通过@Param 注解指定的名字

  2.有多个参数

第 2 章中讲过,当有多个参数的时候,要使用@Param 注解给每个参数指定一个名字,否则在 SQL 中使用参数时就会不方便,因此将 collection 设置为@Param 注解指定的名字即可

  3.参数是 Map 类型

使用 Map 和使用@Param 注解方式类似,将 collection 指定为对应 Map 中的 key 即可。如果要循环所传入的 Map,推荐使用@Param 注解指定名字,此时可将 collection 设置为指定的名字,如果不想指定名字,就使用默认值_parameter

  4.参数是一个对象

这种情况下指定为对象的属性名即可。当使用对象内多层嵌套的对象时,使用 属性.属性(集合和数组可以使用下标取值的方式可以指定深层的属性值

先来看一个简单的测试代码,验证以上说法

    @Test
    public void testSelectByIdList(){
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<Long> idList = new ArrayList<Long>();
            idList.add(1L);
            idList.add(1001L);
            //业务逻辑中必须校验 idList.size() > 0
            List<SysUser> userList = userMapper.selectByIdList(idList);
            Assert.assertEquals(2, userList.size());
        } finally {
            //不要忘记关闭 sqlSession
            sqlSession.close();
        }
    }
public void testSelectByIdList()

相关文章: