Mybatis IF 标签整型判空潜在的坑

文章讲述了在使用Mybatis时,如果在if标签中对int或long类型的字段进行判空操作,可能会遇到无法正确触发条件的问题。原因是Mybatis会将Number类型与0进行双精度浮点比较,导致预期的判断失效。作者提供了两种正确的写法,并通过源码分析解释了这个问题的原因,同时给出了ognl表达式测试示例,帮助读者理解和避免此类问题。
摘要由CSDN通过智能技术生成

前言


贴一张 来自 应届生的 瑟瑟发抖的 代码走读的 恐惧:


 

 
大家平时写代码,一定一定要明确,自测 是研发自己的事,不是自己写完就完事咯~

正文

开始进入主题,一起看看怎么个事。


不能暴露业务代码,我就简单来举例复现一下。

大概是这样 


小伙设计了一个表,表里面 设计了一个字段 代表 启用 停用 :

STATE   1:启用  0:停用  ,默认 1 启用

然后呢, 写了个根据 state 状态查询的 方法  : getDistrictByState


根据枚举 启用 、停用 配合 mybatis 的if 标签判空 来触发 这个查询条件,做数据查询。


表:

注意到,state 是 int 类型 (其实long类型也一样有该篇说的坑)

mapper:

 xml :

(红色框住的,if标签 对于 int long 这些数据的判空,这样写是有坑的! 前排警告!!!)

 

然后代码是这样写的:

看看数据表里面的数据 :

那么正常来说,就应该查出来这三条,因为 传入参数不是空,然后触发sql if 拼接:

 而现实是全给查出来了, 因为条件没触发 :

为什么?

在为什么之前,我先列出这种整型(int long) if标签,如果想写判空触发,正确写法是 :

方案一

        <if test="state!= null ">
             STATE= #{state}
        </if>



 方案二

        <if test="state!= null and state!= '' or state == 0">
             STATE= #{state}
        </if>

 

再回到为什么?

原理很简单,就是mybatis框架的代码的固定逻辑 :

只要if 标签 传入的 是 Number 类型数据 , 就会使用双精度浮点类型 跟 0 比较, 如果不等于 0 才 触发, 否则就是 不触发。


小伙写法传入的就是  0 , 然后if 标签 的写法 state != null and state != '' " 。 就应证了上面的说法。

当然口说无凭,现在出来混,讲证据:

Any object can be used where a boolean is required. OGNL interprets objects as booleans like this:

  • If the object is a Boolean, its value is extracted and returned;
  • If the object is a Number, its double-precision floating-point value is compared with zero; non-zero is treated as true, zero as false;
  • If the object is a Character, its boolean value is true if and only if its char value is non-zero;
  • Otherwise, its boolean value is true if and only if it is non-null.

翻译:
如果对象是数字,则将其双精度浮点值与零进行比较;非零视为true,零视为false.

false的话 那当然就不触发咯。

经常看我文章的人,显然是知道的,我不止这么点。 我很干。 

我们接下来看看 mybatis 源码怎么说?

debug,进源码,不啰嗦。

if标签解析,;来自于mybatisjar 里面的 IfSqlNode.java  :

位置 :org.apache.ibatis.scripting.xmltags.IfSqlNode

看到了一开始,拿到了小伙 针对整型,可能是复制粘贴别人代码 写的if 标签 :

 

然后是 ExpressionEvaluator.java  的 evaluateBoolean函数 :

位置 : org.apache.ibatis.scripting.xmltags.ExpressionEvaluator

接着看 OgnlCache.java的 getValue函数 :

OgnlCache.getValue(expression, parameterObject);

位置 :org.apache.ibatis.scripting.xmltags.OgnlCache

 继续点进去,看看

parseExpression(expression)

 把我们的 传参 state 为 0,传入 就是相当于是:

(0 != null )&& ( 0!= '')

自己玩一玩,当前情况的if 标签, 我们传入 0  还有传入 1,是怎么会回事? 

就是硬核,我们直接把代码拿出来玩!

pom 文件 加入 :
 

<dependency>
    <groupId>ognl</groupId>
    <artifactId>ognl</artifactId>
    <version>2.7</version>
</dependency>

写个测试方法,眼见为实: 

    public static void main(String[] args) throws ognl.OgnlException {

        Object o = ognl.Ognl.parseExpression("0 != null and 0 != ''");
        Object result = Ognl.getValue(o, null);
        System.out.println("触发结果是 :" + result);

        Object o1 = ognl.Ognl.parseExpression("1 != null and 1 != ''");
        Object result1 = Ognl.getValue(o1, null);
        System.out.println("触发结果是 :" + result1);
    }



该篇就到这 ,每个人不同角度看我的文章,关注点也许不一样,但是我希望我能传达、分享更多的东西给到大家。 点赞、收藏、评论,让我看看你们在支持我。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小目标青年

对你有帮助的话,谢谢你的打赏。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值