mybatis结合MySQL的CTE语句进行批量更新

1、需求复现

后端接口接收一个Collection实体类列表,想要根据实体类里面的某个字段(非主键)进行批量更新,后端使用的是mybatis。

2、技术复现

由于是复现代码随便建的表,字段展示就随便展示几个,主要走流程,看逻辑

2-1 建表

sql 复制代码
create table i_test_user
(
    user_id             bigint      not null primary key comment '用户id 主键',
    nick_name           varchar(32) not null comment '昵称',
    chat_account_number varchar(12) not null comment '聊天账户,类似QQ号',
    phone_number        varchar(11) not null comment '手机号'
)

2-2 后端实体类

后端实体类我用的是VO来接收的,由于是需要用户下载导出我们的数据为一个excel,然后在里面进行数据修改,故userId这些字段我就未展示给用户的Excel,只展示了nickName,chatAccountNumber,phoneNumber,其中chatAccountNumber是处于保护的,即无法进行修改的。

java 复制代码
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Accessors
public class ITestUserVo implements Serializable {
    private static final long serialVersionUID = 1L;
 
    /**
     * 昵称
     */
    @ExcelProperty(value = "昵称")
    private String nickName;
 
    /**
     * 聊天账户
     */
    @ExcelProperty(value = "聊天账户")
    private String chatAccountNumber;
 
 
    /**
     * 手机号
     */
    @ExcelProperty(value = "手机号")
    private String phoneNumber;
 
}

2-3 后端service层代码

为了省事,不写接口了,直接展示接口实现类方法,该方法并不是直接上传Excel后调用的方法,该方法是读取完Excel的数据后进行批量更新的方法。

java 复制代码
 public Result updateUploadDataBatch(Collection<ITestUserVo> dataList) {
        if (CollUtil.isEmpty(dataList)) {
            return Result.error("数据为空");
        }
        boolean b = this.baseMapper.updateBatchByPhoneNumber(dataList);
        if (!b) {
            return Result.error("更新上传的数据失败");
        }
        return Result.ok("更新上传的数据成功");
    }

2-4 Dao层接口

java 复制代码
 boolean updateBatchByPhoneNumber(@Param("dataList") Collection<ITestUserVo> dataList);

2-5 sql实现

xml 复制代码
<sql id="tmpCTE">
        <foreach collection="dataList" item="item" separator=" UNION ">
            select #{item.nickName} AS nickName, #{item.chatAccountNumber} AS chatAccountNumber,#{item.phoneNumber} AS phoneNumber
        </foreach>
</sql>
 
 
 
<update id="updateBatchByPhoneNumber">
        with tmp_table(nickName, chatAccountNumber, phoneNumber) AS (
        <include refid="tmpCTE"/>
        )
        update i_test_user a
        set 
            a.nick_name = (select aa.nickName from tmp_table aa where aa.chatAccountNumber =
        a.chat_account_number limit 1),
            a.phone_number = (select aa.phoneNumber from tmp_table aa where aa.chatAccountNumber =
        a.chat_account_number limit 1)
        where a.chat_account_number IN (select chatAccountNumber from tmp_table)
</update>

3、总结

spring结合mybatis使用mysql的with...as的CTE语法实现批量更新,首先使用with...as建立一个临时表进行更新,这样可以减少数据库的IO次数吧,比起foreach批量更新数据也算提供一个新的思路吧。后期优化的话其实可以实现分批次进行更新,具体批次大小还是要根据项目数据以及数据库的io瓶颈进行测试决定吧,这些都是后期封装成一个工具类的话进行考虑的了。

相关推荐
鹏程十八少13 分钟前
13. Android 面了50位Kotlin候选人,这36个语法坑90%的人答不全
前端·后端·面试
东宇科技17 分钟前
用CladueCode来玩tp8+swoole(常用案例)
后端·swoole
Shadow(⊙o⊙)23 分钟前
硬核手搓解析!进程-内核分析:命令行参数及环境变量,重构main()
linux·运维·服务器·开发语言·c++·后端·学习
毋语天26 分钟前
Claude Code 完整安装与配置指南(含 CC-Switch 多供应商切换工具)
后端·python·ai编程
StackNoOverflow27 分钟前
RabbitMQ 入门详解(含安装 + 配置 + 管理后台)
开发语言·后端·ruby
养肥胖虎9 小时前
Docker学习笔记:后端、数据库和反向代理怎么一起跑起来
后端·nginx·docker·postgresql·go·部署
晓杰'10 小时前
从0到1实现 Balatro 游戏后端(2):NestJS框架搭建与项目结构设计
后端·websocket·typescript·node.js·游戏开发·项目实战·nestjs
无所事事O_o10 小时前
二次验证码TOTP 使用说明
后端·二次验证码·谷歌验证器
ltl11 小时前
Multi-Head Attention:为什么要分多个头
后端
ltl11 小时前
Scaled Dot-Product:那个根号 d_k 是怎么来的'
后端