MySql使用case when then end where 关键字执行批量更新(batchUpdate)时的避坑指南

前一段做一个批量更新的需求,数据的来源是一个Excel文件,列有值的话,就更新,没值的话,就忽略。

首先可以使用mybatis-plus的com.baomidou.mybatisplus.extension.service包下的IService接口里面的批量方法

但它的实现原理是伪批量,所以我参照系统中之前的批量更新写法,写了一个Mysql自带的批量更新,Map.xml中的代码如下:

<!--  批量修改product_online表(线上商品池)Excel中某列数据有值,所有行的该列数据都必须得有值,否则会被设置为该类型的默认值 -->
    <update id="batchUpdateProductOnline" parameterType="java.util.List">
        UPDATE product_online
        <trim prefix="set" suffixOverrides=",">
            <trim prefix="product_name = case" suffix="end,"> <!-- 线上商品名称 -->
                <foreach collection="list" item="item">
                    <if test='item.productName != null'>
                        when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.productName,jdbcType=VARCHAR}
                    </if>
                </foreach>
            </trim>
            <trim prefix="product_specific = case" suffix="end,"> <!-- 规格 -->
                <foreach collection="list" item="item">
                    <if test='item.productSpecific != null'>
                        when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.productSpecific,jdbcType=VARCHAR}
                    </if>
                </foreach>
            </trim>
            <trim prefix="product_unit = case" suffix="end,"> <!-- 单位 -->
                <foreach collection="list" item="item">
                    <if test='item.productUnit != null'>
                        when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.productUnit,jdbcType=VARCHAR}
                    </if>
                </foreach>
            </trim>
            <trim prefix="weight = case" suffix="end,"> <!-- 毛重 -->
                <foreach collection="list" item="item">
                    <if test='item.weight != null'>
                        when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.weight,jdbcType=DECIMAL}
                    </if>
                </foreach>
            </trim>
            <trim prefix="origin_place = case" suffix="end,"> <!-- 产地 -->
                <foreach collection="list" item="item">
                    <if test='item.originPlace != null'>
                        when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.originPlace,jdbcType=VARCHAR}
                    </if>
                </foreach>
            </trim>
            <trim prefix="shelf_life = case" suffix="end,"> <!-- 保质期 -->
                <foreach collection="list" item="item">
                    <if test='item.shelfLife != null'>
                        when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.shelfLife,jdbcType=VARCHAR}
                    </if>
                </foreach>
            </trim>
            <trim prefix="product_brief = case" suffix="end,"> <!-- 商品简述 -->
                <foreach collection="list" item="item">
                    <if test='item.productBrief != null'>
                        when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.productBrief,jdbcType=VARCHAR}
                    </if>
                </foreach>
            </trim>
            <trim prefix="storage_type = case" suffix="end,"> <!-- 储藏方式 -->
                <foreach collection="list" item="item">
                    <if test='item.storageType != null'>
                        when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.storageType,jdbcType=VARCHAR}
                    </if>
                </foreach>
            </trim>
            <trim prefix="is_return = case" suffix="end,"> <!-- 是否支持退换货 -->
                <foreach collection="list" item="item">
                    <if test='item.isReturn != null'>
                        when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.isReturn,jdbcType=TINYINT}
                    </if>
                </foreach>
            </trim>
            <trim prefix="sub_title = case" suffix="end,"> <!-- 商品副标题 -->
                <foreach collection="list" item="item">
                    <if test='item.subTitle != null'>
                        when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.subTitle,jdbcType=VARCHAR}
                    </if>
                </foreach>
            </trim>
            <trim prefix="keywords = case" suffix="end,"> <!-- 商品关键词 -->
                <foreach collection="list" item="item">
                    <if test='item.keywords != null'>
                        when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.keywords,jdbcType=VARCHAR}
                    </if>
                </foreach>
            </trim>
            <trim prefix="updated_time = case" suffix="end,"> <!-- 更新时间 -->
                <foreach collection="list" item="item">
                    when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.updatedTime}
                </foreach>
            </trim>
            <trim prefix="updated_by = case" suffix="end,"> <!-- 操作人 -->
                <foreach collection="list" item="item">
                    when product_code = #{item.productCode,jdbcType=VARCHAR} then #{item.updatedBy,jdbcType=VARCHAR}
                </foreach>
            </trim>
        </trim>
        <where>  <!-- 使用 case when then end语句 批量更新时,where条件是必须的,不然默认会更新所有的,把原值覆盖成默认值!! -->
            <foreach collection="list" separator="or" item="item">
                product_code = #{item.productCode,jdbcType=VARCHAR}
            </foreach>
        </where>
    </update>

但这种方式有两个大坑!!

1号坑:使用 case when then end语句 批量更新时,where条件是必须的,不然默认会更新所有的,把原值覆盖成数据库类型的默认值!!

2号坑:我的数据来源是一个Excel文件,比如说Excel文件中共100行数据,其中只要有一行数据 在第3列有值,那么批量更新的时候,这100行数据的第3列都必须得有值,不然的话,数据库会把其他第3列的值覆盖成数据库类型的默认值!!

鉴于这两个坑的存在,我在批量更新前,就必须得先去数据库中查,得到查询结果的List,然后对每个列进行非空检验,如果为空,就把数据库中的值赋给该列,这样就可以避免 误操作篡改数据了。

这个功能上线后,我心里还是很忐忑的,必经update操作一定要谨慎,但最近观察一段时间的使用后,生产上没出现数据问题,哈哈

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值