mybatis IDEA——foreach标签

SQL语句中有时会使用IN关键字,例如id in ( 1, 2, 3)。可以使用${ids}方式直接获取值,但这种写法不能防止SQL注入,想避免SQL注入就需要用#{}的方式,这时就要配合使用foreach标签来满足需求。
foreach可以对数组、Map或实现了iterable接口(如List、 Set)的对象进行遍历。数组在处理时会转换为List对象,因此foreach遍历的对象可以分为两大类: Iterable类型和Map 类型。这两种类型在遍历循环时情况不一样。

1、foreach实现in集合

foreach实现in集合(或数组)是最简单和常用的一种情况,下面介绍如何根据传入的用户id集合查询出所有符合条件的用户。foreach包含以下属性:
collection: 必填,值为要选代循环的属性名。这个属性值的情况有很多。
item:变量名,值为从法代对象中取出的每一个值。
index:索引的属性名,在集合数组情况下值为当前索引值, 当选代循环的对象是Map类型时,这个值为Map的key (键值)。
open:整个循环内容开头的字符串。
close: 整个循环内容结尾的字符串。
separator:每次循环的分隔符。
当参数类型为数组的时候,也会转换成Map类型,默认的key为array。当使用数组参数时,就需要把foreach标签中的collection属性值设置为array。
List<SysUser> selectByidList(Long[]  idArray); 
上面提到的是数组或集合类型的参数默认的名字。推荐使用@Param来指定参数的名字,这时collection就设置为通过@Param注解指定的名字。
说明:
(1)当有多个参数或者参数为Map类型时,最好通过@Param注解为参数指定名字。
(2)当参数是一个对象时,这种情况下指定为对象的属性名即可。当使用对象内多层嵌套的对象时,使用属性.属性(集合和数组可以使用下标取值)的方式可以指定深层的属性值。

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

测试

    @Test
    public void testQueryByids(){
        try(SqlSession session = this.getSqlSession()){
            SysUserDao userDao = session.getMapper(SysUserDao.class);
            List<Long> ids = new ArrayList<>();
            ids.add(1L);
            //ids.add(1001L);
            ids.add(100L);
            List<SysUser> list = userDao.queryByids(ids);
            System.out.println(list);
        }
    }

日志

DEBUG [main] - Cache Hit Ratio [com.etc.dao.SysUserDao]: 0.0
Fri Sep 07 18:51:34 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
DEBUG [main] - ==>  Preparing: select * from sys_user where id in ( ? , ? ) 
DEBUG [main] - ==> Parameters: 1(Long), 100(Long)
TRACE [main] - <==    Columns: id, user_name, user_password, user_email, create_time
TRACE [main] - <==        Row: 1, admin, 123456, [email protected], 2018-01-01 00:00:00.0
Mon Jan 01 00:00:00 CST 2018
DEBUG [main] - <==      Total: 1
[SysUser{id=1, userName='admin', userPassword='123456', userEmail='[email protected]', createTime1=Mon Jan 01 00:00:00 CST 2018, roles=null, role=null}]

2、foreach实现批量插入

如果数据库支持批量插入,就可以通过foreach来实现。批量插入是SQL-92新增的特性,目前支持的数据库有DB2、SQL Server 2008及以上版本、MySQL等。
批量插入的语法如下:
INSERT  INTO  tablename  (column-a,  [column-b,  ... ] ) 
VALUES  (’value-la ’, [ ’ value-lb’,...]), 
(’value-2a’, [ ’ value-2b’,...]), 
从待处理部分可以看出,后面是一个值的循环,因此可以通过foreach实现循环插入。

如果要在MySQL中实现批量插入返回自增主键值, 只需要在原来代码基础上进行如下修改即可。

<insert id=”insertList” useGeneratedKeys=”true ” keyProperty=”id”>
  <insert id="insertList">
    insert into sys_user
    (user_name,user_password,user_email,create_time)
    values
    <foreach collection="list" item="user" separator=",">
      (#{user.userName},#{user.userPassword},#{user.userEmail},
      #{user.createTime,jdbcType=TIMESTAMP})
    </foreach>
  </insert>

测试

    @Test
    public void testInsertList(){
        try(SqlSession session = this.getSqlSession()){
            SysUserDao userDao = session.getMapper(SysUserDao.class);
            List<SysUser> users = new ArrayList<>();
            users.add(new SysUser("test2","654321","[email protected]",null));
            users.add(new SysUser("test3","654321","[email protected]",null));
            int result = userDao.insertList(users);
            //session.commit();
            Assert.assertTrue(result == 2);
        }
    }

日志

Fri Sep 07 19:06:01 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
DEBUG [main] - ==>  Preparing: insert into sys_user(user_name,user_password,user_email,create_time) values (?,?,?,?) , (?,?,?,?) 
DEBUG [main] - ==> Parameters: test2(String), 654321(String), [email protected](String), null, test3(String), 654321(String), [email protected](String), null
DEBUG [main] - <==    Updates: 2
    <insert id="insertList2">
        insert into sys_user(user_name,user_password,user_email,create_time)
        <foreach collection="list" item="user" separator=" union all ">
            select #{user.userName},#{user.userPassword},#{user.userEmail},#{user.createTime1}
        </foreach>
    </insert>

 测试类

    @Test
    public void testInsertList2(){
        try(SqlSession session = this.getSqlSession()){
            SysUserDao userDao = session.getMapper(SysUserDao.class);
            List<SysUser> users = new ArrayList<>();
            users.add(new SysUser("test2","654321","[email protected]",null));
            users.add(new SysUser("test3","654321","[email protected]",null));
            int result = userDao.insertList2(users);
            session.commit();
            Assert.assertTrue(result == 2);
        }
    }

日志

Fri Sep 07 19:13:57 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
DEBUG [main] - ==>  Preparing: insert into sys_user(user_name,user_password,user_email,create_time) select ?,?,?,? union all select ?,?,?,? 
DEBUG [main] - ==> Parameters: test2(String), 654321(String), [email protected](String), null, test3(String), 654321(String), [email protected](String), null
DEBUG [main] - <==    Updates: 2

3、foreach实现动态update

当参数类型是Map时, foreach如何实现动态UPDATE 。
当参数是Map类型的时候,foreach标签的工ndex属性值对应的不是索引值,而是Map中的key,利用这个key可以实现动态UPDATE。
现在需要通过指定的列名和对应的值去更新数据。

  <update id="updateByMap">
    update sys_user
    set
    <foreach collection="_parameter" item="val" index="key" separator=",">
      ${key} =  #{val}
    </foreach>
    where id =  #{id}
  </update>

接口 

    int updateByMap(@Param("map") Map<String,Object> map);

测试

    @Test
    public void testUpdateByMap(){
        try(SqlSession session = this.getSqlSession()){
            SysUserDao dao = session.getMapper(SysUserDao.class);
            Map<String,Object> map = new HashMap<>();
            map.put("user_name","test666");
            map.put("user_password","654321");
            map.put("id",1001L);
            int result = dao.updateByMap(map);
            Assert.assertTrue(result == 1);
        }
    }

日志

Fri Sep 07 19:10:14 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
DEBUG [main] - ==>  Preparing: update sys_user set user_password = ? , user_name = ? , id = ? where id=? 
DEBUG [main] - ==> Parameters: 654321(String), test666(String), 1001(Long), 1001(Long)
DEBUG [main] - <==    Updates: 1

猜你喜欢

转载自blog.csdn.net/Milan__Kundera/article/details/82501257
今日推荐