mybatis批量插入之找不到对应字段属性

探讨MyBatis批量插入数据时的常见错误与正确做法,解析为何不能对字段值进行条件判断的原因。

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

##第一种:错误写法

<!--
    <insert id="batchInsert" parameterType="xxx">
        insert into xxx
        <trim prefix="(" suffix=")" suffixOverrides=",">
            
            <if test="ERID != null">
                erid,
            </if>
          
            <if test="orderNo != null">
                order_no,
            </if>
          
        </trim>
        VALUES
        <foreach collection="list" item="item" open="" close=""
            separator=",">
            <trim prefix="(" suffix=")" suffixOverrides=",">
            
                <if test="item.ERID != null">
                    #{item.ERID,jdbcType=VARCHAR},
                </if>
             
                <if test="item.orderNo != null">
                    #{item.orderNo,jdbcType=VARCHAR},
                </if>
              
            </trim>
        </foreach>
    </insert> -->

##第二种:正确写法

<insert id="batchInsert" parameterType="xxx">

<!--注意这里参数类型写成java.util.List和具体对象类型,都可以正常插入数据-->
        insert into monitor_er_info(
                erid,
                order_no)
        VALUES
        <foreach collection="list" item="item" open="" close=""
            separator=",">
            (
                    #{item.ERID,jdbcType=VARCHAR},              
                    #{item.orderNo,jdbcType=VARCHAR},
                   
        )
        </foreach>
    </insert>

你可能也会像我一样,既然单个数据的插入有一个insertSelective,为什么在批量插入的时候不可以有呢?于是你可能就会试着写一段代码,比如上图中的第一种,乍一看,好像也没有什么问题,但是当你运行代码的过程中,就会报一个错误,那就是:

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'ERID' not found. Available parameters are [collection, list]

提示无法找到对应的参数ERID,其实不是只是这一个找不到,后面的参数都找不到的。

于是我们就想,这个ERID是封装实体类中的一个属性,按照第二种方式可以正常插入数据,那么就能说明,批量插入的值的传递,其写法是正确。也就foreach中,定义的是一个集合,它的item就是集合中的对象,对象的属性值就是我们想要插入的字段值。因此只能是insert后面values之前的对象属性无法找到对应的属性才会报错,为了验证我们的思想,我们可以把那些判断条件去掉。再试一次。于是就变成了下面这样。

<insert id="batchInsert" parameterType="xxx">
        insert into monitor_er_info
        <trim prefix="(" suffix=")" suffixOverrides=",">         
                erid,       
                order_no,
              
        </trim>
        VALUES
        <foreach collection="list" item="item" open="" close=""
            separator=",">
            <trim prefix="(" suffix=")" suffixOverrides=",">
            
                <if test="item.ERID != null">
                    #{item.ERID,jdbcType=VARCHAR},
                </if>              
                <if test="item.orderNo != null">
                    #{item.orderNo,jdbcType=VARCHAR},
                </if>              
            </trim>
        </foreach>
    </insert>

在运行的过程中,我们可以发现,没有报相关的属性找不到了(因为我们传递的是list,insert后面它没有直接去对象中找相关的属性了,也就是没有list.ERID了,而是直接写死的,就是指定插入这些字段的值),说明我们刚才的推想是正确的。但是这样就面临一个问题,那就是属性上没有加入判断,而插入的值对其相应的属性做了判断,这就导致,所有的插入的字段与传递的值的数量可能会出现不一致的情况。当然对象也都可以设置默认值作为解决,但这样下面的判断不就显得多余了吗?

这里的报错内容是:

org.springframework.jdbc.UncategorizedSQLException:
### Error updating database.  Cause: java.sql.SQLException: [e1dc03feac00000-2][172.169.101.107:3306][mysql1]ERR-CODE: [TDDL-4501][ERR_OPTIMIZER] optimize error by Column count doesn't match value count More:

因此走到这里,我们写出正确的代码就是第二种,但是这偏离了我们的意愿,我是想对批量插入的字段进行判断的,难道真的就不可以了吗!!!事实上就是不可以

且看:我们定义的接口中的方法:

int batchInsert(List<MonitorErInfo> list);

再次想一下:集合中具体的对象这里为MonitorErInfo,它的属性值是ERID,workStatus等这些,我们想加入的判断条件是因为这些属性的值是否存在存在不确定性。这体现到sql中就明显了,对于单个数据的插入,在insert和values后面对相关的属性进行判断,这样的话,无论如何insert后面的字段数量和values后面的需要插入的值,都是一一对应的,不多也不少。

但是针对批量插入,这就不行了。实际上批量插入执行的sql是这样的

insert into tableA(x,y,z) values (a,b,c),(d,e,f),(h,j,k), (...)

sql不支持这样的语句,比如

insert into tableA(x,y,z) values(a),(b,c),(d,e,f)

道理很简单,比如a,你怎么知道这个值是插入到x,y还是z呢!

你有可能想到占位,比如可以这样写

insert into tableA(x,y,z) values(a,null,null),(null,b,c),(d,e,f)

但是这样不就是回到第二种方法了吗!我们判断的条件依旧没有加上啊!

既然values后面无法使用,那么在insert后面values之前做做手脚呢?

其实也是行不通的,insert后面如果不指定数据库字段的名称,那么values后面即使指定了它的值也是插入不进去的,即便插入进去了,也不是那个字段对应的值了,不对应了,因此,如果values后面的属性值不确定,那么如果全部的属性都有值的话,意味着,insert后values之前的数据库字段都应该存在。再结合之前的分析,如果这些字段都有存在,要保证插入的数据值和字段一一对应,那么values必须每个位上都有值,这就意味着,我们无法通过属性判断,来决定哪些值需要插入,哪些值不需要插入。属性值的判断也就失去了意义!

综上!针对批量插入,我们无法使用可选择属性,针对性插入的方法!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值