foreach 實現 MyBatis 遍歷集合與批量運算元據

留蘭香丶發表於2018-03-13

一、寫在前面

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

相關文章