mybatis批量新增和更新mysql数据

本文分享了在项目中遇到的批量新增和更新业务场景下,如何通过自定义MyBatis XML语句优化批量操作效率的经验。从原来的60秒缩短至5秒,通过对比不同写法的效率,详细介绍了如何利用foreach标签进行批量更新和插入,以及在大量数据处理时如何避免堆栈溢出的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:项目中遇到批量新增和更新的业务,大概更新2万条,新增3万条。之前为了进度,直接使用mybatis-plus自带的批量新增(saveBatch)和更新(saveOrUpdateBatch)执行时间60秒,直接奔溃了。摒弃mybatis自带的批量处理方式,自己写xml语句,执行时间缩短为5秒左右,优化方案如下:
sql连接配置添加&allowMultiQueries=true,例如
url: jdbc:mysql://127.0.0.1/med?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&allowMultiQueries=true

批量更新xml语句:

<update id="updateBatch">
    <foreach collection="list" item="item"  separator=";">
        update kl_diagnose_detail
        <set>
            <if test="item.verifyStandard != null">
                verify_standard = #{item.verifyStandard},
            </if>
            <if test="item.verifyRelation != null">
                verify_relation = #{item.verifyRelation},
            </if>
        </set>
        where id = #{item.id}
    </foreach>
</update>

注意:另外还有一种写法是使用case…when,代码如下【效率低下】:

<update id="updateBatch">
    update kl_diagnose_detail
    <trim prefix="set" suffixOverrides=",">
        <trim prefix="verify_standard=case" suffix="end,">
            <foreach collection="list" item="item" index="index">
                <if test="item.verifyStandard!=null">
                    when id=#{item.id} then #{item.verifyStandard}
                </if>
            </foreach>
        </trim>
        <trim prefix="verify_relation=case" suffix="end,">
            <foreach collection="list" item="item" index="index">
                <if test="item.verifyRelation!=null">
                    when id=#{item.id} then #{item.verifyRelation}
                </if>
            </foreach>
        </trim>
    </trim>
    where
    <foreach collection="list" separator="or" item="item" index="index">
        id=#{item.id}
    </foreach>
</update>

经本人亲自测试之后,效率远不如第一种写法,而且数据量越大,大量的case…when判断使得执行效率越低,不可取。

批量新增xml语句:

<insert id="insertBatch">
    INSERT INTO kl_diagnose_question(gmt_create, gmt_modified, diagnose_id) VALUES
    <foreach collection="list" item="item" index="index" separator=",">
        (
        #{item.gmtCreate},#{item.gmtModified},#{item.diagnoseId}
        )
    </foreach>
</insert>

另外还有一种写法如下【效率低下】,不可取

<insert id="insertBatch">
    <foreach collection="list" item="item"  separator=";">
        INSERT INTO kl_diagnose_question(gmt_create, gmt_modified, diagnose_id, dis_name, `type`, question_name, question_type, order_no) VALUES
        (
        #{item.gmtCreate},#{item.gmtModified},#{item.diagnoseId},#{item.disName},#{item.type},#{item.questionName},#{item.questionType},#{item.orderNo}
        )
    </foreach>
</insert>

特别注意

如果批量操作的数据特别大,在拼接sql时可能会报堆栈溢出,处理如下:
将原有的List<T> 类型,拆分成List<List<T>>,方法如下,通过循环执行就不会报错。

// 总体代码结构如下
for (int i = 0; i < size; i++) {
	// 批量执行代码;
}

/**
     * sql批量执行时,参数分组后按组提交,避免游标、数据量超过限制
     *
     * @param originList 原始参数列表
     * @param capacity   分组后每组的大小
     * @return List<List   <   T>> 分组后的参数列表
     */
    public static <T> List<List<T>> divideList(List<T> originList, int capacity) {
        List<List<T>> list = new LinkedList<>();
        int originListSize = originList.size();

        int length = originListSize / capacity;
        if (length == 0) {
            list.add(originList);
            return list;
        }
        if (originListSize % capacity > 0) {
            length = length + 1;
        }
        for (int i = 0; i < length; i++) {
            int fromIndex = i * capacity;
            int toIndex = (i + 1) * capacity > originListSize ? originListSize : (i + 1) * capacity;
            list.add(new ArrayList<T>(originList.subList(fromIndex, toIndex)));
        }
        return list;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

屁仙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值