前言
贴一张 来自 应届生的 瑟瑟发抖的 代码走读的 恐惧:
大家平时写代码,一定一定要明确,自测 是研发自己的事,不是自己写完就完事咯~
正文
开始进入主题,一起看看怎么个事。
不能暴露业务代码,我就简单来举例复现一下。
大概是这样
小伙设计了一个表,表里面 设计了一个字段 代表 启用 停用 :
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);
}
该篇就到这 ,每个人不同角度看我的文章,关注点也许不一样,但是我希望我能传达、分享更多的东西给到大家。 点赞、收藏、评论,让我看看你们在支持我。