MyBatis中foreach批量更新返回-1的原因及处理咨询
MyBatis批量更新(逻辑删除)返回-1的原因及解决办法
原因分析
你当前的SQL是将多个UPDATE语句包装在Oracle的PL/SQL匿名块(DECLARE BEGIN ... END;)中执行的。JDBC驱动执行这类匿名块时,默认不会返回DML语句的受影响行数,而是返回-1——因为匿名块本身属于PL/SQL执行单元,并非直接的DML操作,驱动无法直接提取单个或多个UPDATE的影响行数。
你之前认知的“返回第一条SQL执行结果”,仅适用于**不使用PL/SQL块、直接用foreach拼接多个独立UPDATE语句(以分号分隔)**的场景,但Oracle JDBC默认不支持这种多语句执行方式,所以你才需要用PL/SQL块包裹,这也导致了返回值的变化。
解决办法
方案1:改用单条批量UPDATE语句(推荐)
用CASE WHEN实现单条SQL完成批量逻辑删除,既能直接返回受影响的总行数,性能也更优:
<update id="deleteVhcleInfos" parameterType="java.util.List"> UPDATE TB_VHCL_MANAGE SET DEL_YN = 'Y', MDFC_USERNO = CASE <foreach collection="list" item="item" separator=" "> WHEN VHCLNO = #{item.vhclno} THEN #{item.mdfcUserno} </foreach> ELSE MDFC_USERNO END, MDFC_DTTM = CASE <foreach collection="list" item="item" separator=" "> WHEN VHCLNO = #{item.vhclno} THEN SYSDATE </foreach> ELSE MDFC_DTTM END WHERE VHCLNO IN <foreach collection="list" item="item" open="(" separator="," close=")"> #{item.vhclno} </foreach> </update>
注意:需确保传入的list中vhclno非空且唯一,避免更新逻辑冲突。执行后返回的数值就是实际被修改的行数,完全适配你原有的代码判断逻辑。
方案2:保留PL/SQL块并获取总行数
若必须保留原循环写法,可在PL/SQL块中累计受影响行数并通过输出参数返回:
- 修改MyBatis XML:
<update id="deleteVhcleInfos" parameterType="java.util.Map"> DECLARE total_rows NUMBER := 0; BEGIN <foreach collection="list" item="item" separator=" "> UPDATE TB_VHCL_MANAGE <set> <if test='item.vhclno != null and item.vhclno != ""'> DEL_YN = 'Y' </if> <if test='item.mdfcUserno != null and item.mdfcUserno != ""'> , MDFC_USERNO = #{item.mdfcUserno} , MDFC_DTTM = SYSDATE </if> </set> WHERE VHCLNO = #{item.vhclno}; total_rows := total_rows + SQL%ROWCOUNT; </foreach> #{total, mode=OUT, jdbcType=INTEGER} := total_rows; END; </update>
- 修改Mapper接口方法,添加输出参数:
void deleteVhcleInfos(@Param("list") List<VhcleInfo> list, @Param("total") AtomicInteger total);
调用时传入AtomicInteger对象,执行后total.get()即可获取总受影响行数。这种写法相对繁琐,性能也不如方案1。
方案3:调整代码判断逻辑
如果不想修改SQL,可将返回-1视为执行成功(前提是确保执行过程无SQL异常):
int result = vhcleInfoMapper.deleteVhcleInfos(list); // 无异常情况下,返回-1表示PL/SQL块执行成功 if (result == 0) { // 无数据被更新,可根据业务判定为失败或成功 } else if (result < 0) { // 执行成功 } else { // 执行失败 }
注意:这种方式存在风险,若PL/SQL块内部某条UPDATE执行失败但未抛出异常(如未处理的约束违规),代码无法感知,因此不推荐。
内容的提问来源于stack exchange,提问作者sinichee
相关产品推荐
相关产品推荐

