MyBatis foreach 批量更新實(shí)例
在做配置選項(xiàng)(設(shè)備類型,所屬樓層等)的時(shí)候,當(dāng)刪除某配置的時(shí)候,我需要檢驗(yàn)該配置是否已被刪除。
@Override public BaseVO deleteOptionDetail(Integer id) { // 合法性驗(yàn)證 if (null == id) { return ParamErrorVO.getInstance(); } ConfigOptionDetail configOptionDetail = configOptionDetailMapper.selectById(id); if (null == configOptionDetail || 1 == configOptionDetail.getIsDeleted()) { return new ErrorVO('該配置不存在'); } if (configOptionDetail.getSystem() == 1) { return new ErrorVO('系統(tǒng)屬性不能刪除'); } if (configOptionDetail.getUseCount() = 0) { return new ErrorVO('配置正在使用不能刪除,請(qǐng)先刪除使用配置的地方'); } // 合法性通過 configOptionDetail.setIsDeleted(1); configOptionDetail.setGmtModefied(Calendar.getInstance().getTime()); configOptionDetailMapper.updateById(configOptionDetail); // 更新內(nèi)存配置 ConfigOptionConstruct.updateOption(); return SuccessVO.getInstance(); }
思考之后我決定采用,給配置選項(xiàng)設(shè)備一個(gè)use_count字段,代表該配置被引用的次數(shù)。 只有當(dāng)該字段值為 0 時(shí),該配置選項(xiàng)記錄才可被刪除。
我需要批量刪除房間, 刪除房間的同時(shí),room對(duì)象中使用到了所屬樓層的配置選項(xiàng),我需要將他們的引用減少
@Override public BaseVO deleteRoomByIds(Integer[] ids) { if (null == ids) { return ParamErrorVO.getInstance(); } EntityWrapper<Room> entityWrapper = new EntityWrapper<>(); entityWrapper.where('isdelete={0}', 0); // 核查刪除的房間中是否存在正在使用的設(shè)備 List<Integer> notDelete = deviceInfoService.checkRoomIds(ids); if (null != notDelete && 0 != notDelete.size()) { // 存在仍在使用設(shè)備的房間 entityWrapper.in('id', notDelete); // 查詢這些房間 List<Room> roomList = roomMapper.selectList(entityWrapper); // 獲取房間的名稱 StringBuilder stringBuilder = new StringBuilder(roomList.stream().map(Room::getName).collect(Collectors.toList()).toString()); System.out.println(stringBuilder); // TODO: 2018/4/8 可能需要修改提示語 return new ErrorVO(stringBuilder + ' 房間存在未刪除的設(shè)備,請(qǐng)先刪除設(shè)備'); } // 房間沒有設(shè)備在使用 List<Integer> idList = new ArrayList<>(); idList.addAll(Arrays.asList(ids)); // 查詢需要?jiǎng)h除的房間 entityWrapper.in('id', idList); List<Room> roomList = roomMapper.selectList(entityWrapper); if (null == roomList || idList.size() != roomList.size()) { return new ErrorVO('存在錯(cuò)誤的房間'); } // ******************************************************************************************** 重點(diǎn) // 可以邏輯刪除 int count = roomMapper.logicDeleteByIds(idList); List<Long> optionIds = roomList.stream().map(room -> Long.parseLong(room.getRoomPosition())).collect(Collectors.toList()); Map<Long, Long> optionIdsMap = optionIds.stream().collect(Collectors.groupingBy(p -> p,Collectors.counting())); // 移除所屬樓層配置選項(xiàng)的使用 configOptionDetailService.removeUseCount(optionIdsMap); ConfigOptionConstruct.updateOption(); if (count == idList.size()) { return SuccessVO.getInstance(); } else { return new ErrorVO('部分刪除失敗'); } }
optionIds 是從roomList 房間集合中,通過stream, 所引用的配置選項(xiàng)id集合
上面我紅字標(biāo)明他們,是因?yàn)椋绻块gA 是一樓, 房間B 也是一樓, 那么我應(yīng)該將一樓的引用減 2。
所以我將optionIds 分組轉(zhuǎn)成Map<配置選項(xiàng)id, 需要減少引用的次數(shù)>
最后一步,也是最重要的進(jìn)行數(shù)據(jù)庫操作,我希望可以批量更新減少這些引用。
查看MyBatis文檔:
foreach動(dòng)態(tài) SQL 的另外一個(gè)常用的操作需求是對(duì)一個(gè)集合進(jìn)行遍歷,通常是在構(gòu)建 IN 條件語句的時(shí)候。比如:
<select resultType='domain.blog.Post'> SELECT * FROM POST P WHERE ID in <foreach item='item' index='index' collection='list' open='(' separator=',' close=')'> #{item} </foreach></select>
foreach 元素的功能非常強(qiáng)大,它允許你指定一個(gè)集合,聲明可以在元素體內(nèi)使用的集合項(xiàng)(item)和索引(index)變量。它也允許你指定開頭與結(jié)尾的字符串以及在迭代結(jié)果之間放置分隔符。這個(gè)元素是很智能的,因此它不會(huì)偶然地附加多余的分隔符。
注意 你可以將任何可迭代對(duì)象(如 List、Set 等)、Map 對(duì)象或者數(shù)組對(duì)象傳遞給 foreach 作為集合參數(shù)。當(dāng)使用可迭代對(duì)象或者數(shù)組時(shí),index 是當(dāng)前迭代的次數(shù),item 的值是本次迭代獲取的元素。當(dāng)使用 Map 對(duì)象(或者 Map.Entry 對(duì)象的集合)時(shí),index 是鍵,item 是值。
<update id='addUseCountByIds'> update config_option_detail set gmt_modified = #{gmtModified}, use_count = use_count + <foreach item='item' index='index' collection='list' open=' case id ' separator=' ' close=' end'> when #{index} then #{item} </foreach> where id in <foreach item='item' index='index' collection='list' open='(' separator=',' close=')'> #{index} </foreach></update>
補(bǔ)充:mybatis 用<foreach>根據(jù)ID批量更新時(shí)的一個(gè)注意點(diǎn)。
看接口。傳入一個(gè)Long型的List。
int updateReadCount(@Param(value = 'topicIdList') List<Long> topicIdList);
xml里面循環(huán)update.
<update parameterType='java.util.List'> update CTS set read_count = read_count + 1 where topic_id in <foreach item='item' index='index' collection='topicIdList' open='(' close=')' separator=','> #{item.topicId} </foreach> </update>
就是直接復(fù)制了別人的代碼,改了一改。怎么都跑不通。。。。。。。
問題就出在這個(gè)item,item 表示集合中每一個(gè)元素進(jìn)行迭代時(shí)的別名。
List<Long> topicIdList 因?yàn)闀r(shí)Long型(不是entity封裝著的),就不需要?jiǎng)e名了。改為如下就可以跑通了。
<update parameterType='java.util.List'> update CTS set read_count = read_count + 1 where topic_id in <foreach item='topicId' index='index' collection='topicIdList' open='(' close=')' separator=','> #{topicId} </foreach> </update>
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持好吧啦網(wǎng)。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章:
1. mysql 實(shí)現(xiàn)添加時(shí)間自動(dòng)添加更新時(shí)間自動(dòng)更新操作2. Db2數(shù)據(jù)庫中常見的堵塞問題分析與處理方法3. Oracle如何在SQL語句中對(duì)時(shí)間操作、運(yùn)算4. MySql中 is Null段判斷無效和IFNULL()失效的解決方案5. access的備注字段限制64K6. Mysql獲取指定時(shí)間范圍數(shù)據(jù)的各種實(shí)例7. debian10 mariadb安裝過程詳解8. MySQL Flink Watermark實(shí)現(xiàn)事件時(shí)間處理的關(guān)鍵技術(shù)9. 一文總結(jié)MySQL中數(shù)學(xué)函數(shù)有哪些10. MySQL性能壓力基準(zhǔn)測(cè)試工具sysbench的使用簡(jiǎn)介
