MyBatis动态SQL中数值0更新失效问题解析与解决方案
作者:尽兴-
本文详细解析了MyBatis动态SQL中数值字段更新失效的问题,指出使用FastJSON的JSONObject接收入参时应避免混用字符串、数字判断,并提出两种解决方案,推荐采用数值字段最优方案,需要的朋友可以参考下

一、问题现象
业务场景为物料库存更新接口,使用 FastJSON 的 JSONObject 接收入参,MyBatis 动态 SQL 通过 <if> 标签判断字段是否参与更新:
- 入参
newQuantity传入数值0(Integer 类型); - XML 中判断条件:
<if test="newQuantity != null and newQuantity != ''">; - 最终打印的执行 SQL 完全没有拼接
invt = #{newQuantity}这一段,库存字段未更新; - 当
newQuantity传入大于 0 的数字(如 2、5)时,SQL 正常拼接,更新逻辑生效。
二、根因分析
1. OGNL 表达式底层判定规则
MyBatis 的 <if test> 使用 OGNL 表达式做条件判断,当数字 0 与**空字符串 ''**做不等对比时:0 != '' 的运算结果为 false。
完整条件 newQuantity != null and newQuantity != '' 逻辑拆解:
- newQuantity=0,
newQuantity != null→ true; newQuantity != ''→ false;true && false整体条件不成立,<if>分支直接跳过,对应字段不会拼入 SQL。
2. 混用字符串、数字判断是核心误区
!= '' 是专门用于字符串类型的判空逻辑,用来过滤前端传过来的空字符串 "";
而库存、金额、单价、税额这类字段,存储类型为 Integer/BigDecimal,入参只会是 null 或数字,永远不会出现空字符串,强行叠加 != '' 判断会拦截数值 0。
3. 同类受影响字段
代码中所有金额、数值字段都存在相同隐患:amount_inclusive_tax、unit_pr、amount_tax、amount_no_tax,当传入 0 时都会出现更新失效。
三、两种解决方案
方案 1:数值字段最优方案(推荐)
数字类型字段仅判断 null,直接删除 != '' 条件,不做空字符串校验:
<!-- 库存数量(Integer) -->
<if test="newQuantity != null">
invt = #{newQuantity},
</if>
<!-- 含税金额(BigDecimal) -->
<if test="amount_inclusive_tax != null">
amount_inclusive_tax = #{amount_inclusive_tax},
</if>优势:逻辑简洁、无多余运算,完美兼容 0、正数、负数等所有数字场景。
方案 2:兼容字符串 + 数字混合入参场景
若字段存在同时接收字符串、数字的特殊场景,补充数字 0 的判断逻辑:
<if test="newQuantity != null and (newQuantity != '' or newQuantity == 0)">
invt = #{newQuantity},
</if>劣势:多一层逻辑判断,纯数值业务不推荐使用。
四、规范区分:什么时候用!= '',什么时候只用!= null
- 字符串字段(名称、编码、备注、地址)
需要双重判断,过滤null和前端空字符串:
<if test="artiName != null and artiName != ''">
arti_name = #{artiName},
</if>
- 数值字段(Integer、Long、BigDecimal、Double)
仅判断非 null,禁止加!= '':
<if test="changeQuantity != null">
invt = #{changeQuantity},
</if>五、修正后完整 XML 示例
<update id="updateInvtQuantity" parameterType="com.alibaba.fastjson.JSONObject">
UPDATE LCP_ARTI_MATN_HQZX
SET
<if test="newQuantity != null">
invt = #{newQuantity},
</if>
<if test="amount_inclusive_tax != null">
amount_inclusive_tax = #{amount_inclusive_tax},
</if>
<if test="unit_pr != null">
unit_pr = #{unit_pr},
</if>
<if test="amount_tax != null">
amount_tax = #{amount_tax},
</if>
<if test="amount_no_tax != null">
amount_no_tax = #{amount_no_tax},
</if>
sysupdatedate = SYSDATE,
sysupdateoruuid = #{syscreatoruuid},
sysupdateoruuidname = #{syscreatoruuidname}
WHERE matn_id = #{matnId}
AND sysisdelete = '0'
</update>六、总结避坑要点
- 数字字段不要混用空字符串判断
!= '',会拦截数值 0; - 严格区分字段类型,字符串双重判空、数值仅判 null;
- 开发完成后务必覆盖入参为 0 的场景做单元测试,避免库存清零、金额置零等业务逻辑失效;
- 打印 MyBatis 执行 SQL 日志辅助排查动态分支是否正常拼接。
以上就是MyBatis动态SQL中数值0更新失效问题解析与解决方法的详细内容,更多关于MyBatis动态SQL数值0更新失效的资料请关注脚本之家其它相关文章!
