MyBatis foreach 批量更新實例
在做配置選項(設(shè)備類型,所屬樓層等)的時候,當(dāng)刪除某配置的時候,我需要檢驗該配置是否已被刪除。
@Override
public BaseVO deleteOptionDetail(Integer id) {
// 合法性驗證
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("配置正在使用不能刪除,請先刪除使用配置的地方");
}
// 合法性通過
configOptionDetail.setIsDeleted(1);
configOptionDetail.setGmtModefied(Calendar.getInstance().getTime());
configOptionDetailMapper.updateById(configOptionDetail);
// 更新內(nèi)存配置
ConfigOptionConstruct.updateOption();
return SuccessVO.getInstance();
}
思考之后我決定采用,給配置選項設(shè)備一個use_count字段,代表該配置被引用的次數(shù)。 只有當(dāng)該字段值為 0 時,該配置選項記錄才可被刪除。

使用情況:
我需要批量刪除房間, 刪除房間的同時,room對象中使用到了所屬樓層的配置選項,我需要將他們的引用減少
@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è)備,請先刪除設(shè)備");
}
// 房間沒有設(shè)備在使用
List<Integer> idList = new ArrayList<>();
idList.addAll(Arrays.asList(ids));
// 查詢需要刪除的房間
entityWrapper.in("id", idList);
List<Room> roomList = roomMapper.selectList(entityWrapper);
if (null == roomList || idList.size() != roomList.size()) {
return new ErrorVO("存在錯誤的房間");
}
// ******************************************************************************************** 重點
// 可以邏輯刪除
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()));
// 移除所屬樓層配置選項的使用
configOptionDetailService.removeUseCount(optionIdsMap);
ConfigOptionConstruct.updateOption();
if (count == idList.size()) {
return SuccessVO.getInstance();
} else {
return new ErrorVO("部分刪除失敗");
}
}
optionIds 是從roomList 房間集合中,通過stream, 所引用的配置選項id集合
上面我紅字標(biāo)明他們,是因為,如果房間A 是一樓, 房間B 也是一樓, 那么我應(yīng)該將一樓的引用減 2。
所以我將optionIds 分組轉(zhuǎn)成Map<配置選項id, 需要減少引用的次數(shù)>
最后一步,也是最重要的進行數(shù)據(jù)庫操作,我希望可以批量更新減少這些引用。
查看MyBatis文檔:
foreach
動態(tài) SQL 的另外一個常用的操作需求是對一個集合進行遍歷,通常是在構(gòu)建 IN 條件語句的時候。比如:
<select id="selectPostIn" 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 元素的功能非常強大,它允許你指定一個集合,聲明可以在元素體內(nèi)使用的集合項(item)和索引(index)變量。它也允許你指定開頭與結(jié)尾的字符串以及在迭代結(jié)果之間放置分隔符。這個元素是很智能的,因此它不會偶然地附加多余的分隔符。
注意 你可以將任何可迭代對象(如 List、Set 等)、Map 對象或者數(shù)組對象傳遞給 foreach 作為集合參數(shù)。當(dāng)使用可迭代對象或者數(shù)組時,index 是當(dāng)前迭代的次數(shù),item 的值是本次迭代獲取的元素。當(dāng)使用 Map 對象(或者 Map.Entry 對象的集合)時,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>
補充:mybatis 用<foreach>根據(jù)ID批量更新時的一個注意點。
看接口。傳入一個Long型的List。
int updateReadCount(@Param(value = "topicIdList") List<Long> topicIdList);
xml里面循環(huán)update.
<update id="updateReadCount" 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ù)制了別人的代碼,改了一改。怎么都跑不通。。。。。。。
問題就出在這個item,item 表示集合中每一個元素進行迭代時的別名。
List<Long> topicIdList 因為時Long型(不是entity封裝著的),就不需要別名了。改為如下就可以跑通了。
<update id="updateReadCount" 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>
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
使用RestTemplate調(diào)用https接口跳過證書驗證
這篇文章主要介紹了使用RestTemplate調(diào)用https接口跳過證書驗證,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10
Netty分布式NioEventLoop優(yōu)化selector源碼解析
這篇文章主要介紹了Netty分布式NioEventLoop優(yōu)化selector源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03
java 學(xué)習(xí)筆記(入門篇)_java程序helloWorld
安裝配置完Java的jdk,下面就開始寫第一個java程序--hello World.用來在控制臺輸出“Hello World”,接下來詳細介紹,感興趣的朋友可以參考下2013-01-01
SpringBoot中配置Web靜態(tài)資源路徑的方法
這篇文章主要介紹了SpringBoot中配置Web靜態(tài)資源路徑的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Java 高并發(fā)編程之最實用的任務(wù)執(zhí)行架構(gòu)設(shè)計建議收藏
高并發(fā)(High Concurrency)是互聯(lián)網(wǎng)分布式系統(tǒng)架構(gòu)設(shè)計中必須考慮的因素之一,它通常是指,通過設(shè)計保證系統(tǒng)能夠同時并行處理很多請求,高并發(fā)相關(guān)常用的一些指標(biāo)有響應(yīng)時間(Response Time),吞吐量(Throughput),每秒查詢率QPS(Query Per Second),并發(fā)用戶數(shù)等2021-10-10
使用Spring Data Jpa的CriteriaQuery一個陷阱
使用Spring Data Jpa的CriteriaQuery進行動態(tài)條件查詢時,可能會遇到一個陷阱,當(dāng)條件為空時,查詢不到任何結(jié)果,并不是期望的返回所有結(jié)果。這是為什么呢?2020-11-11
Sping?Security前后端分離兩種實戰(zhàn)方案
這篇文章主要介紹了Sping?Security前后端分離兩種方案,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03

