mybatis 批量update、batchUpdate、case when update

1、foreach写法

注意⚠️
foreach需要在db链接url后面带一个参数 &allowMultiQueries=true

举个例子:
url: jdbc:mysql://127.0.0.1:3306/my_tb?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false

这种写法适用于批量修改为同一种状态

   /**
     * 根据学生状态批量修改学生们的课程情况
     *
     * @param courseInfo       课程情况
     * @param studenMark       学业情况
     * @param list             学生id列表
     * @param studentStatus    学生状态
     */
    void batchUpStuInfo(@Param("courseInfo") String courseInfo, @Param("studenMark") String studenMark, @Param("list") List<Long> list, @Param("studentStatus") Integer studentStatus);

    <update id="batchUpStuInfo">
        update student_info
           set course_info     = #{courseInfo},
               student_mark    = #{studenMark}
        where `student_status` = #{studentStatus}
        and `id` in
        <foreach collection="list" close=")" open="(" separator="," item="item">
            #{item}
        </foreach>
    </update>

2、case when 写法

适用于对象值不同进行批量修改

   /**
     * 批量修改学生情况
     *
     * @param list 学生实体信息列表
     */
    void batchUpStuInfo(@Param("list") List<StuPO> list);
    <update id="batchUpStuInfo">
        update student_info
        <set>
            <trim prefix="course_info = case" suffix="end,">
                <foreach collection="list" item="item">
                <if test="item.courseInfo != null">
                    when id=#{item.id} then #{item.courseInfo}
                </if>
                <if test="item.courseInfo == null">
                    when id=#{item.id} then course_info  -- 若传入的属性为null,则保持数据库原值
                </if>
                </foreach>
            </trim>
            <trim prefix="student_mark = case" suffix="end,">
                <foreach collection="list" item="item">
                    <if test="item.studentMark != null">
                        when id=#{item.id} then #{item.studentMark}
                    </if>
                    <if test="item.studentMark == null">
                        when id=#{item.id} then student_mark
                    </if>
                </foreach>
            </trim>
        </set>
        where `id` in
        <foreach collection="list" item="item" index="index" separator="," open="(" close=")">
            #{item.id}
        </foreach>
    </update>

3、效率问题

  • 很明显,foreach循环体效率要高很多,因为它仅有一个循环体,第二种虽然最后只会有一条更新语句,但是xml中的循环体有点多,每一个case when 都要循环一遍list集合,所以大批量拼sql的时候会比较慢。

  • 但是这两种方式,数据量大之后都会导致SQL阻塞,建议分批进行执行。

推荐 分批工具类链接

在这里插入图片描述

### MyBatis 中使用 `update` 和 `foreach` 拼接超长字符串的优化方案 在 MyBatis 中,当需要通过 `update` 和 `foreach` 拼接超长字符串时,可能会遇到性能问题或 SQL 语句过长的问题。以下是几种常见的优化方案: #### 1. 使用数据库支持的批量更新功能 某些数据库(如 MySQL、PostgreSQL)支持批量更新操作。可以通过将多个更新操作合并为一个事务来减少网络开销和提升性能[^1]。例如,在 MyBatis 中可以使用以下方式实现批量更新: ```xml <update id="batchUpdate" parameterType="java.util.List"> UPDATE your_table <set> <foreach collection="list" item="item" separator=","> column_name = CASE id WHEN #{item.id} THEN #{item.value} </CASE> </foreach> </set> WHERE id IN <foreach collection="list" item="item" open="(" close=")" separator=","> #{item.id} </foreach> </update> ``` 这种方式通过 `CASE` 语句动态生成 SQL,避免了重复调用单条 `UPDATE` 语句。 #### 2. 分批处理超长字符串 如果字符串长度超出数据库或 JDBC 驱动的限制,可以考虑分批次处理数据。例如,将数据分成多个较小的批次进行更新,每个批次包含一定数量的记录[^2]。以下是一个示例代码: ```java public void batchUpdate(List<YourEntity> entities, int batchSize) { for (int i = 0; i < entities.size(); i += batchSize) { List<YourEntity> subList = entities.subList(i, Math.min(entities.size(), i + batchSize)); mapper.batchUpdate(subList); } } ``` #### 3. 使用存储过程 对于非常复杂的更新逻辑,可以考虑将更新逻辑移至数据库端,通过存储过程完成。这种方式不仅可以减少 SQL 拼接的工作量,还能充分利用数据库的性能优势[^3]。以下是一个简单的存储过程示例: ```sql CREATE PROCEDURE update_batch(IN ids TEXT, IN values TEXT) BEGIN UPDATE your_table SET column_name = CASE WHEN FIND_IN_SET(id, ids) > 0 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(values, ',', FIND_IN_SET(id, ids)), ',', -1) ELSE column_name END WHERE FIND_IN_SET(id, ids) > 0; END; ``` 在 MyBatis 中调用存储过程的方式如下: ```xml <insert id="callUpdateBatch" statementType="CALLABLE"> {CALL update_batch(#{ids}, #{values})} </insert> ``` #### 4. 优化 MyBatis 的 `foreach` 配置 MyBatis 的 `foreach` 标签会生成大量重复的 SQL 片段,可能导致性能下降。可以通过调整 `open`、`close` 和 `separator` 属性来减少冗余内容[^4]。例如: ```xml <update id="updateWithForeach" parameterType="java.util.List"> UPDATE your_table SET column_name = CASE <foreach collection="list" item="item" separator=" "> WHEN id = #{item.id} THEN #{item.value} </foreach> END WHERE id IN <foreach collection="list" item="item" open="(" close=")" separator=","> #{item.id} </foreach> </update> ``` #### 5. 数据库字段类型优化 如果目标字段是文本类型(如 `VARCHAR` 或 `TEXT`),确保其长度足够大以容纳拼接后的字符串。同时,避免频繁更新超长字符串,因为这可能会导致索引失效或存储空间膨胀[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值