1. 程式人生 > >MyBatis3+ 實現批量更新

MyBatis3+ 實現批量更新

要實現批量更新,首先得設定mysql支援批量操作,在jdbc連結中需要附加&allowMultiQueries=true屬性才行
例如:
jdbc:mysql://localhost:3306/dbname?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true

  • 更新單條記錄
    UPDATE course SET name = 'course1' WHERE id = 'id1';
  • 更新多條記錄的同一個欄位為同一個值
    UPDATE course SET name = 'course1' WHERE id in ('id1', 'id2', 'id3);
  • 更新多條記錄為多個欄位為不同的值
    比較普通的寫法,是通過迴圈,依次執行update語句。
    Mybatis寫法如下:
<update id="updateBatch"  parameterType="java.util.List">  
    <foreach collection="list" item="item" index="index" open="" close="" separator=";">
        update course
        <set>
            name=${item.name}
        </set
>
where id = ${item.id} </foreach> </update>

一條記錄update一次,效能比較差,容易造成阻塞。

  • MySQL沒有提供直接的方法來實現批量更新,但可以使用case when語法來實現這個功能。
UPDATE course
    SET name = CASE id 
        WHEN 1 THEN 'name1'
        WHEN 2 THEN 'name2'
        WHEN 3 THEN 'name3'
    END, 
    title = CASE
id WHEN 1 THEN 'New Title 1' WHEN 2 THEN 'New Title 2' WHEN 3 THEN 'New Title 3' END WHERE id IN (1,2,3)

這條sql的意思是,如果id為1,則name的值為name1,title的值為New Title1;依此類推。

在Mybatis中的配置則如下:

<update id="updateBatch" parameterType="list">
     update course
      <trim prefix="set" suffixOverrides=",">
       <trim prefix="peopleId =case" suffix="end,">
           <foreach collection="list" item="i" index="index">
                   <if test="i.peopleId!=null">
                    when id=#{i.id} then #{i.peopleId}
                   </if>
           </foreach>
        </trim>
        <trim prefix=" roadgridid =case" suffix="end,">
           <foreach collection="list" item="i" index="index">
                   <if test="i.roadgridid!=null">
                    when id=#{i.id} then #{i.roadgridid}
                   </if>
           </foreach>
        </trim>

        <trim prefix="type =case" suffix="end," >
           <foreach collection="list" item="i" index="index">
                   <if test="i.type!=null">
                    when id=#{i.id} then #{i.type}
                   </if>
           </foreach>
        </trim>
        <trim prefix="unitsid =case" suffix="end," >
            <foreach collection="list" item="i" index="index">
                    <if test="i.unitsid!=null">
                     when id=#{i.id} then #{i.unitsid}
                    </if>
            </foreach>
     </trim>
    </trim>
    where
    <foreach collection="list" separator="or" item="i" index="index" >
        id=#{i.id}
    </foreach>
</update>

上面是使用xml配置檔案進行的批量修改,另外,更詳細的介紹可以參考這位老哥哥的部落格
下面看使用註解如何寫批量更新操作:

使用註解批量更新

首先定義批量更新的介面,引數使用@Param註解界定;

public interface WarningMapper {
    @UpdateProvider(method = "updateBatch", type = WarningProvider.class)
    int updateBatch(@Param(value = "list") List<WarningModel> records);
}

提供provider:

class WarningProvider {
    public String updateBatch(final Map<String, List<WarningModel>> map) {
        List<WarningModel> records = map.get("list");//注意這裡引數是map獲取list
        StringBuilder sb = new StringBuilder();
        sb.append("update " + TABLE_NAME);
        sb.append(" set now_value = case appid");//這裡可以仿照set now_value 設定其他值的修改
        MessageFormat mfNowValue = new MessageFormat("#'{'list[{0}].now_value'}'");
        for (int i = 0; i < records.size(); i++) {
            sb.append(" when ");
            sb.append(records.get(i).getAppid());
            sb.append(" then ");
            sb.append(mfNowValue.format(new Object[] { i }));
        }
        sb.append(" end ");
        sb.append("where appid in");
        sb.append("(");
        for (int size = 0; size < records.size(); size++) {
            sb.append(records.get(size).getAppid());
            if (size < records.size() - 1) {
                sb.append(",");
            }
        }
        sb.append(")");
        return sb.toString();
    }
}

上面主要注意表示式"#'{'list[{0}].now_value'}'"的使用

批量插入操作也可以參考批量更新,比較簡單不需要case語句


這裡在介紹一下Mybatis的常用註解

MyBatis常用註解

@Options常用屬性:

  • flushCache:重新整理快取策略,有DEFAULT,TRUE,FALSE三種值,預設DEFAULT表示重新整理查詢語句的快取
  • useCache:預設true,表示使用快取
  • fetchSize:查詢時的獲取數量
  • useGeneratedKeys:預設false,是否返回插入的id
  • keyProperty:實體類id屬性
  • keyColumn:實體類屬性對應資料庫的欄位

舉例:一個插入資料操作的mapper定義如下:

public interface WarningMapper {

    @Insert(value = "insert into dtjx_warning"
            + " (trans_id,monitor_type,creator,created,filter,version)"
            + " values (#{trans_id},#{monitor_type},#{creator},#{created},#{filter},version+1)")
    @Options(keyProperty = "appid", useGeneratedKeys = true, keyColumn = "appid") // 用options屬性的useGenerateKeys可以返回自動增長的主鍵資訊
    int insert(WarningModel record);
}

更多註解使用方法,請參考官方文件