四、Mybatis动态插入之foreach插入、实现in集合、优化等

1、使用场景

​ 在实际开发过程中,我们经常需要批量更新或者是批量查询,此时如果逐条插入,将影响效率。所以通常我们都是将其封装为一个集合,再进行插入。主要以下三种方式:

  1. foreach 实现批量插入
  2. foreach 实现in集合
  3. foreach 实现动态update,与插入类似。
  4. foreach优化

2、foreach属性介绍

  1. collection:指定要遍历的集合。入参为list,collection为list;入参为数组,collection为array;入参为map,collection为集合的名称;不过你写collection也可以。
  2. index:循环索引,遍历l数组或者集合时,该值为当前索引值;遍历map的时候index表示的就是map的key,item就是map的值。
  3. item:将当前遍历出的元素赋值给指定的变量,可以理解成变量中的user。
  4. open:循环以什么开始。
  5. close:循环以什么结束。
  6. separator:循环内容之间以什么分隔。

3、foreach实现insert批量插入

​ 在此之前,要配置好maven环境,增加junit、log4j(便于调试测试)依赖,具体可以看我之前写的文章:https://blog.csdn.net/weixin_35798336/article/details/111052348

测试类:

@Test
    public void insertsTest(){
        List<User> users= new ArrayList<User>();
        /*将user加入集合为了演示,实际项目中不可能出现该类重复代码*/
        User user = new User(11,"as","sds",10);
        User user1 = new User(12,"as","sds",0);
        User user2 = new User(13,"as","sds",0);
        User user3 = new User(14,"as","sds",0);
        User user4 = new User(15,"as","sds",0);
        users.add(user);
        users.add(user1);
        users.add(user2);
        users.add(user3);
        users.add(user4);
        /*调用mapper接口*/
        mapper.insertUsers(users);
        sqlSession.commit();
    }

接口方法:

int insertUsers(List<User> users);

xml映射文件:

<insert id="insertUsers">
    insert into user (id , name ,password, `delete`) values
    /*此处collection处一般按照实际类型填写,此处本应填写list,演示所用;item处即为下列中的user.id中的user。*/
    /*insert into user (id , name ,password, `delete`) values (?,?,?,?) , (?,?,?,?) , (?,?,?,?) , (?,?,?,?) , (?,?,?,?),foreach中的代码即为values中要写的重复代码,separator就是每一次迭代中要增加的符号。*/
    <foreach collection="collection" item="user" separator=",">
        (#{user.id},#{user.name},#{user.password},#{user.delete})
    </foreach>
</insert>

4、foreach 实现in集合

​ in集合一般使用的场景为客户或者系统运维人员需要拉取某批指定id的用户的数据,此时,我们需要用in。

java代码:

@Test
    public void selectIdsTest(){
        List<Integer> ids= new ArrayList<Integer>();
        /*将user加入集合为了演示,实际项目中不可能出现该类重复代码*/
        ids.add(12);
        ids.add(13);
        ids.add(14);
        ids.add(15);
        /*调用mapper接口*/
        List<User> user = mapper.findAllByIds(ids);
        for (User user1 : user) {
            System.out.println(user);
        }
        sqlSession.commit();
    }
List<User> findAllByIds(List<Integer> ids);//接口方法
<select id="findAllByIds" resultType="User">
        /*这是要显示的语句:所以以open和close来做开始结束。select * from user where id in (11,12,13,14)*/
        select * from user where id in
        <foreach collection="list" item="ids" open ="(" close=")" separator=",">
            #{ids}
        </foreach>
    </select>

4、优化,不同方式对于执行速度的影响(数据量大的情况)

  1. 就是以上代码的执行方法。

  2. 在代码中拼接字符串,作为参数传入配置文件中,在配置文件中将 通过 ${xxx} 来获取:

    <select id="findAllByIds" resultType="User">
        select * from user
        <where>
            <if test="ids != null and ids != ''">
          	and id in ${ids}
        	</if>
        </where>
        </select>
    
  3. 在配置文件中 通过 #{xxx} 来获取:

    代码与上面的类似,仅把${ids}修改为#{ids}。

总结:在数据量非常大的时候解析的速度为方式1<方式2<方式3。

​ 简单来说foreach这么慢的原因是因为foreach实际上是把语句变成了:

select  *  from  user where  id in (#{__frch_item_0},  #{__frch_item_1}, #{__frch_item_2}, #{__frch_item_3}, #{__frch_item_4})

​ 而关于#与$的区别,即两种符号其实分别对应的是jdbc中的PreparedStatment 对象和Statment 对象。当使用 Statement 对象时,每次执行一个SQL命令时,都会对它进行解析和编译。而PreparedStatment 表示预编译的SQL,包含的SQL已经预编译过了,SQL 中的参数部分使用 进行占位。所以之后的sql进行大数据的传入时,可以将数据分批拼接传入。


版权声明:本文为weixin_35798336原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。