1.需求描述
公司需要在定时任务中处理大量数据,最后更新的数据量可能有几万条。所以需要进行批量更新。
2.mybatis批量更新
先贴出批量更新sql
<update id="batchUpdate" parameterType="java.util.List">
update fm_news_newsdynamic
<trim prefix="set" suffixOverrides=",">
<trim prefix="review_count =case" suffix="end,">
<foreach collection="list" item="item" index="index">
<if test="item.reviewCount !=null">
when news_id=#{item.newsId} then review_count+#{item.reviewCount}
</if>
</foreach>
</trim>
<trim prefix="collect_count =case" suffix="end,">
<foreach collection="list" item="item" index="index">
<if test="item.collectCount !=null">
when news_id=#{item.newsId} then collect_count+#{item.collectCount}
</if>
</foreach>
</trim>
</trim>
where news_id in
<foreach collection="list" index="index" item="item" separator="," open="(" close=")">
#{item.newsId}
</foreach>
</update>
上面这个sql只是拿两个字段进行示范,实际更新的字段更多。
然后,我们来解析一下这些sql标签是什么意思
<trim prefix="set" suffixOverrides=",">
使用<trim>
标签动态构建SET
部分,prefix="set"
表示前缀为set
,suffixOverrides=","
表示删除最后一个逗号。
更新review_count
字段的case语句:
<trim prefix="review_count = case" suffix="end,">
:
动态构建review_count
的case
语句,前缀为review_count = case
,后缀为end,
。
<foreach collection="list" item="item" index="index">
:
遍历参数列表list
,item
表示每个元素,index
表示索引。
<if test="item.reviewCount != null">
:
仅当reviewCount
不为null
时生成相应的SQL。
when news_id = #{item.newsId} then review_count + #{item.reviewCount}
:
对于每个item
,根据news_id
匹配,更新review_count
。
collect_count
字段和review_count
字段更新逻辑相同
解析后的sql如下:
update fm_news_newsdynamic
set
review_count = case
when news_id = 1 then review_count + 10
when news_id = 2 then review_count + 20
end,
collect_count = case
when news_id = 1 then collect_count + 5
when news_id = 3 then collect_count + 15
end
where news_id in (1, 2, 3)
解析后的sql,虽然不是单纯的拼接update语句,但也需要对更新字段进行case when判断。如果news_id很多的话,解析后的sql也是很庞大的。
所以在service层我们还可以对处理的list集合进行分割。用分割后小的list进行批量更新。
2.Lists.partition集合分割
我们处理的list如果数据量比较大,可以对它进行分割。可以进行手动分割,先设定每个小的list大小,然后根据总的数量计算有多少个小的list,不过这样比较麻烦。
Google Guava 库中有一个静态方法partition,用于将一个大的列表分割成多个大小相等的子列表。如果原始列表的大小不能被分割大小整除,则最后一个子列表的大小可能会小于指定的大小。这在处理大数据集或需要对列表进行批量操作时非常有用。
假设我们有一个列表,需要将其分割成大小为 3 的子列表:
import com.google.common.collect.Lists;
import java.util.List;
public class Example {
public static void main(String[] args) {
List<Integer> numbers = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<List<Integer>> partitioned = Lists.partition(numbers, 3);
for (List<Integer> part : partitioned) {
System.out.println(part);
}
}
}
//输出结果如下:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10]