洞察探索如何通过一套代码实现跨平台小程序开发与高效管理,助力企业数字化转型
2633
2022-10-22
mybatis if test条件判断语句中的判断问题分析
目录iftest条件判断语句中的判断问题我在mybatis中定义的sql语句如下或使用equals()mybatis中iftest判断大坑使用Mybatis时,常常会判断属性是否为空原因分析
if test条件判断语句中的判断问题
写这个主要是描述在mybatis中要注意的问题,很不幸,自己没注意,跳坑了。
我在mybatis中定义的sql语句如下
and z.serviceCount = 1
and z.serviceCount = 0
可以看到这里只是对传入参数一个简单的判断。
controller层传入一个Integer类型的facilityOccupied参数。
表面上看没什么问题,当传入facilityOccupied = 1,测试结果很意外,它查询了所有的结果,也就是说它没有符合这个判断facilityOccupied == 1 。
换一种写法,在controller层中将传入参数facilityOccupied改为String类型的,通过查询结果可以看出它符合facilityOccupied == 1 这个判断条件。
或使用equals()
and z.serviceCount = 1
and z.serviceCount = 0
所以,总结起来怎么说,在这个地方比较的并不是数值大小,而是物理地址,这个双引号里面的1不是int类型也不是integer类型,而是String字符串类型,啊多么痛的领悟。
补充一下,test中eq 和 == 效果一样,比较的是地址,所以比较值最好使用equals()。
mybatis 中if test判断大坑
【
单个的字符要写到双引号里面才行,改为
.xml文件的部分代码
insert cx_customer_deliverypreference
.... 此处省略
WORKDAY,
....
.... 此处省略
#{workday, jdbcType=VARCHAR},
....
takeWay == “1”处出错,导致不执行if判断中的sql,运行程序不报错,没有任何提示。去掉takeWay == “1” and 则可执行。对此我百思不得其解,
因为自己有写过如下代码,是没错的。
......
把
原因是:mybatis是用OGNL表达式来解析的,在OGNL的表达式中,’1’会被解析成字符,java是强类型的,char 和 一个string 会导致不等,所以if标签中的sql不会被解析。
总结下使用方法:单个的字符要写到双引号里面或者使用.toString()才行!
使用Mybatis时,常常会判断属性是否为空
POJO
private Integer status;//状态,可能为0、1、2、3。
Mapper XML
//...省略其他
当status的值为 0时该where SQL and status = 0并未正常拼接,也就是说test内的表达式为false,从而导致查询结果错误。但是,显然该值(Integer :0)!= null也!= ' ',应该为true才对。当status为Integer类型,并且status值为0时,该if判断却为false。当status为0时,Mybatis会解析成'' 空字符串。
为了避免这个问题,改成下面这样写,去掉对空字符的判断,就解决了该问题
原因分析
通过Debug MyBatis源码顺藤摸瓜找到了IfSqlNode类,该类用来处理动态SQL的
public class IfSqlNode implements SqlNode {
private ExpressionEvaluator evaluator;
private String test;
private SqlNode contents;
public IfSqlNode(SqlNode contents, String test) {
this.test = test;
this.contents = contents;
this.evaluator = new ExpressionEvaluator();
}
public boolean apply(DynamicContext context) {
if (evaluator.evaluateBoolean(test, context.getBindings())) {
contents.apply(context);
return true;
}
return false;
}
}
打开ExpressionEvaluator 类,发现解析表达式使用的是OGNL,如果你使用过古老的Struts框架你应该对它不陌生。通过OgnlCache.getValue(expression, parameterObject);可以看到表达式的值是从缓存中获取的,由此可知MyBatis竟然对表达式也做了缓存,以提高性能。
public class ExpressionEvaluator {
public boolean evaluateBoolean(String expression, Object parameterObject) {
Object value = OgnlCache.getValue(expression, parameterObject);
if (value instanceof Boolean) return (Boolean) value;
if (value instanceof Number) return !new BigDecimal(String.valueOf(value)).equals(BigDecimal.ZERO);
return value != null;
}
跟进去看看,终于找到了解析表达式的方法private static Object parseExpression(String expression),该方法会先从缓存取值,如果没有便进行解析并放入缓存中,然后调用Ognl.getValue(parseExpression(expression), root)获得表达式的值。
public class OgnlCache {
private static final Map
public static Object getValue(String expression, Object root) throws OgnlException {
return Ognl.getValue(parseExpression(expression), root);
}
private static Object parseExpression(String expression) throws OgnlException {
try {
Node node = expressionCache.get(expression);
if (node == null) {
node = new OgnlParser(new StringReader(expression))-LevelExpression();
expressionCache.put(expression, node);
}
return node;
} catch (ParseException e) {
throw new ExpressionSyntaxException(expression, e);
} catch (TokenMgrError e) {
throw new ExpressionSyntaxException(expression, e);
}
}
至于Ognl.getValue(parseExpression(expression), root)是如何运作的,如果你有兴趣可以自行跟下去一探究竟,本文就不赘述了。到此为止,我们已经知道MyBatis的表达式是用OGNL处理的了,这一点已经够了。下面我们去OGNL官网看看是不是我们的表达式语法有问题从而导致该问题的发生。
Interpreting Objects as Booleans
Any object can be used where a boolean is required. OGNL interprets objects as booleans like thiCTfKAMMNps:
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.
果然,如果对象是一个Number类型,值为0时将被解析为false,否则为true,浮点型0.00也是如此。OGNL对于boolean的定义和javascript有点像,即'' == 0 == false。这也就不难理解
将表达式修改为
这里有必要再提一个“坑”,如果你有类似于String str ="A";
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~