今天有了新的需求,需求内容是要读取表内的1000条数据,然后批量增加到另一张表,并且把查到的这1000条数据批量删除,说到这里,我就想到了forEach标签,因为自己的记性不太好,因此写一篇博客,记录一下,以后可以直接用。forEach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。
forEach元素的属性主要有 item,index,collection,open,separator,close。
item表示集合中每一个元素进行迭代时的别名,循环体中的具体对象。支持属性的点路径访问,如item.age,item.info.details。 具体说明:在list和数组中是其中的对象,在map中是value,该参数为必选。
index指定一个名字,用于表示在迭代过程中,每次迭代到的位置。在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选。
open表示该语句以什么开始。foreach代码的开始符号,一般是(和close=")"合用。常用在in(),values()时。该参数可选。
separator表示在每次进行迭代之间以什么符号作为分隔符。元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。
close表示以什么结束。foreach代码的关闭符号,一般是)和open="("合用。常用在in(),values()时。该参数可选。
在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况 下,该属性的值是不一样的,主要有一下3种情况:
1. 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
2. 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
3. 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在breast里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key。下面就以我自己写的需求为例,话不多说,上代码:
首先是Mapper接口类, insertBatch和deleteBatchByFileId这两个方法是批量操作方法,这里要注意,一定要有@Param注解,来给集合起一个名字
/**
* 功能描述 //TODO 查询t_res_send_file表中状态为2的1000条数据
* @author 王弈程
* @date 2021/12/20 11:18
* @return: java.util.List<com.unicom.resinteractive.api.service.ResSendFileService>
*/
List<ResSendFile> findStatusIs2();
/**
* 功能描述 //TODO 把从t_res_send_file表中查询到状态为2的1000条数据批量插入到t_res_send_file_history表中
* @author 王弈程
* @date 2021/12/20 11:36
* @param resSendFileHistory:
* @return: void
*/
void insertBatch(@Param("list") List<ResSendFileHistory> resSendFileHistory);
/**
* 功能描述 //TODO 把从t_res_send_file表中读取读取到的resSendFileId放到List中,并且执行批量删除
* @author 王弈程
* @date 2021/12/20 14:06
* @param resSendFileId: 文件领取数据表ID
* @return: int
*/
int deleteBatchByFileId(@Param("list") List<Long> resSendFileId);
接下来是Mapper映射文件,这里我也说明一下,parameterType这里是List或者实体类都可以,但是forEach里面的collection=“list”,这个list必须是Mapper接口类里面每个SQL语句对应的方法里面的形参列表@Param(“list”)对应起来
<select id="findStatusIs2" resultMap="BaseResultMap2">
select
<include refid="Base_Column_List" />
from t_res_send_file
where status = 2
limit 1000
</select>
<insert id="insertBatch" parameterType="com.unicom.resinteractive.po.ResSendFileHistory">
insert into t_res_send_file_history
(res_send_file_id, resorder_no, system_id,
jackpot_code, open_id, send_time,
status, fail_desc, province_code,
eparchy_code, create_time, update_time,
note)
values
<foreach collection="list" item="item" index="index" separator=",">
(#{item.resSendFileId,jdbcType=BIGINT}, #{item.resorderNo,jdbcType=VARCHAR},
#{item.systemId,jdbcType=VARCHAR}, #{item.jackpotCode,jdbcType=VARCHAR},
#{item.openId,jdbcType=VARCHAR}, #{item.sendTime,jdbcType=TIMESTAMP},
#{item.status,jdbcType=INTEGER}, #{item.failDesc,jdbcType=VARCHAR},
#{item.provinceCode,jdbcType=VARCHAR}, #{item.eparchyCode,jdbcType=VARCHAR},
#{item.createTime,jdbcType=TIMESTAMP}, #{item.updateTime,jdbcType=TIMESTAMP},
#{item.note,jdbcType=VARCHAR})
</foreach>
</insert>
<delete id="deleteBatchByFileId">
delete
from t_res_send_file
where res_send_file_id in
<foreach collection="list" item="item" index="index" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
接下来就是业务逻辑,非常简单的逻辑
/**
* 功能描述 //TODO 从t_res_send_file查询出状态为2的1000条数据批量存到t_res_send_file_history表中,并从t_res_send_file表中删除
* @author 王弈程
* @date 2021/12/20 14:18
* @return: void
*/
@Override
public void insertSendFileHistory() {
while(true){
//首先查询t_res_send_file表中状态度为2的数据
List<ResSendFile> statusIs2 = resSendFileHistoryMapper.findStatusIs2();
if (statusIs2 == null){
return;
} else {
//存从statusIs2遍历出来的对象
List<ResSendFileHistory> resSendFileHistoryList = new ArrayList<>();
//存从statusIs2遍历出来的文件ID
List<Long> resSendFileId = new ArrayList<>();
//遍历statusIs2,并且把得到的值赋值给resSendFileHistory,赋值完成后,add到resSendFileHistoryList
for (ResSendFile resSendFile : statusIs2) {
ResSendFileHistory resSendFileHistory = new ResSendFileHistory();
resSendFileHistory.setResSendFileId(resSendFile.getResSendFileId());
resSendFileHistory.setResorderNo(resSendFile.getResorderNo());
resSendFileHistory.setSystemId(resSendFile.getSystemId());
resSendFileHistory.setJackpotCode(resSendFile.getJackpotCode());
resSendFileHistory.setOpenId(resSendFile.getOpenId());
resSendFileHistory.setSendTime(resSendFile.getSendTime());
resSendFileHistory.setStatus(resSendFile.getStatus());
resSendFileHistory.setFailDesc(resSendFile.getFailDesc());
resSendFileHistory.setProvinceCode(resSendFile.getProvinceCode());
resSendFileHistory.setEparchyCode(resSendFile.getEparchyCode());
resSendFileHistory.setCreateTime(resSendFile.getCreateTime());
resSendFileHistory.setUpdateTime(resSendFile.getUpdateTime());
resSendFileHistory.setNote(resSendFile.getNote());
resSendFileHistoryList.add(resSendFileHistory);
resSendFileId.add(resSendFile.getResSendFileId());
}
//批量增加到t_res_send_file_history表中,不考虑其中的某一条数据是否失败
resSendFileHistoryMapper.insertBatch(resSendFileHistoryList);
//批量删除
resSendFileHistoryMapper.deleteBatchByFileId(resSendFileId);
if (statusIs2.size() < 1000){
return ;
}
}
}
}
这里再加入一个批量更新的操作,我感觉实际开发中用处不大
//List类型
<update id="batchUpdateStudent" parameterType="List">
UPDATE STUDENT SET name = "5566" WHERE id IN
<foreach collection="list" item="item" index="index" open="(" separator="," close=")" >
#{item}
</foreach>
</update>
//Map类型
如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在breast里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key
<update id="batchUpdateStudentWithMap" parameterType="Map" >
UPDATE STUDENT SET name = #{name} WHERE id IN
<foreach collection="idList" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</update>