foreach 实现 MyBatis 遍历集合与批量操作数据

一、写在前面

MyBatis 动态 SQL 的一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。foreach允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。foreach 是动态 SQL 中一个非常强大的标签。下面就来体验一下foreach 标签带来的便捷之处,有关批量操作的实现,这里以批量插入数据为例。

二、foreach遍历传递进来的集合

有时候我们可能会有下面的需求,根据多个 id 查询对应的信息,这多个 id 的数量是不固定的。

SELECT * FROM t_employee 
    WHERE id IN (1, 2, 3, ...)

这时候我们可以通过使用foreach标签来遍历集合中的参数,完成多个 id 之间的拼接。

mapper 接口:

    /** 根据传入的 id 集合,查询出对应的员工信息,并使用集合保存信息 */
    List<Employee> getEmpsByConditions(@Param("list") List<Integer> idList);

SQL 映射文件:

    <!-- 注意返回的数据类型是集合中保存的数据类型 Employee-->
    <select id="getEmpsByConditions" resultType="com.jas.mybatis.bean.Employee">
        SELECT * FROM t_employee WHERE id IN 
        <!--
            collection:指定要遍历的集合
            item:取出当前集合中元素,赋给 item 中的值
            separator:遍历出的多个元素之间用什么分隔符分隔开
            open:遍历集合前用什么字符进行拼接
            close:遍历集合后用什么字符进行拼接

            在 foreach 标签中还有一个属性 index,
            遍历集合的时候 index 表示的是当前元素的索引,item 对应索引中的值
            遍历 map 的时候 index 表示的是当前 map 中的 key,item 是 key 对应的 value
        -->
        <foreach collection="list" item="empId" separator="," open="(" close=")">
            #{empId}
        </foreach>
    </select>

测试代码:

    // 用于返回 SqlSession  对象
    private SqlSession getSqlSession() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream is = Resources.getResourceAsStream(resource);

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        return sqlSession;
    }

    @Test
    public void testList() throws IOException {
        SqlSession sqlSession = getSqlSession();

        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> list = employeeMapper.getEmpsByConditions(Arrays.asList(1,2,15));

        for(Employee employee : list){
            System.out.println(employee);
        }

        sqlSession.close();
    }

执行结果:
这里写图片描述

三、foreach批量插入数据

实现foreach批量插入数据有两种方法,一种是只发送一条 SQL,插入的多条数据之间通过”,” 分隔开,另一种方式是每插入一条数据就发送一条 SQL 语句,多个 SQL 语句之间用”;“分割。

3.1 一条 SQL 批量插入数据

mapper 接口:

    /** 返回值为 Integer 类型 */
    Integer addEmpsByList(@Param("list") List<Employee> list);

SQL 映射文件:

    <insert id="addEmpsByList" parameterType="com.jas.mybatis.bean.Employee">
        INSERT INTO t_employee(username, gender, email) VALUES 
        <foreach collection="list" item="emp" separator=",">
            (#{emp.username}, #{emp.gender}, #{emp.email})
        </foreach>
    </insert>

测试代码:

    @Test
    public void testBatchAdd() throws IOException {
        SqlSession sqlSession = getSqlSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> List = new ArrayList<>();

        List.add(new Employee(null, "Jas", '1', "fsd54@qq.com"));
        List.add(new Employee(null, "Jason", '0', "456jhk@qq.com"));

        employeeMapper.addEmpsByList(List);
        sqlSession.commit();

        sqlSession.close();
    }

执行结果:
这里写图片描述

3.2 执行多条 SQL 批量插入数据

修改对应的 SQL 映射文件中的 SQL:

    <insert id="addEmpsByList" parameterType="com.jas.mybatis.bean.Employee">
        <!-- 
            每插入一条数据就执行一次 SQL,中间用";"分隔开 
        -->
        <foreach collection="list" item="emp" separator=";">
            INSERT INTO t_employee(username, gender, email) VALUES 
              (#{emp.username}, #{emp.gender}, #{emp.email})
        </foreach>
    </insert>

MySql 默认的情况下是不支持使用”;” 分隔开多条 SQL 进行执行的,需要设置一个连接属性allowMultiQueries=true来支持。可以在连接数据库的时候设置这个属性。

jdbc.url=jdbc:mysql://localhost:3306/mybatis-study?allowMultiQueries=true

测试代码:

    @Test
    public void testBatchAdd() throws IOException {
        SqlSession sqlSession = getSqlSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> List = new ArrayList<>();

        List.add(new Employee(null, "Tom", '1', "fd@qq.com"));
        List.add(new Employee(null, "Tony", '0', "456fdfjhk@qq.com"));

        employeeMapper.addEmpsByList(List);
        sqlSession.commit();
        sqlSession.close();
    }

执行结果:
这里写图片描述

四、总结

这篇博文主要对 MyBati 动态 SQL 中的foreach进行了介绍与其使用场景的应用,MyBatis 还提供了其他的标签来支持动态 SQL。比如:ifchoose (when, otherwise)trim (where, set),有关的详细信息可以到官方文档进行深入了解,希望这篇博文能够为你提供一些帮助。

动态 SQL 官方文档链接:
http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值