mybatis if判断,mybatis 中使用if else 进行判断
00-1010 if测试的条件判断语句中的判断问题。我在Mybatis中定义的sql语句如下,或者说在equals()mybatis中使用iftest判断坑的时候,我经常判断属性是否为空。原因分析
00-1010写作这主要是描述mybatis中应该注意的问题。可惜我没注意,跳进了坑里。
目录
if test= facility occupated!=null和facilityOccupied!= and facility occupied==1 and z . service count=1/if if test= facility occupied!=null和facilityOccupied!= 和设施发生==0 和z.servicecount=0/if。可以看出,这只是对传入参数的简单判断。
控制器传入整数类型的facilityOccupied参数。
表面上看,没有问题。当incoming facilityOccupied=1时,测试结果是意外的。它查询了所有的结果,也就是说不符合这个判断。设施发生次数==1。
换个说法,在控制器层,将传入参数facility occupy改为String类型,从查询结果可以看出,满足facilityOccupied==1的判断条件。
if test条件判断语句中的判断问题
if test= facility occupated!=null和facilityOccupied!= and facility occuped . equals(1) and z . service count=1/if if test= facility occuped!=null和facilityOccupied!= and facility occurred . equals(0) and z . service count=0/如果是,综上所述,我们在这个地方比较的不是数值大小,而是物理地址。这个双引号中的1不是int类型,也不是integer类型,而是String字符串类型。多么痛苦的认识。
补充一下,test中eq和==的作用是一样的,比较地址,所以比较值最好用equals()。
我在mybatis中定义的sql语句如下
【if test="takeWay == 0"】mybatis的if判断
一个字符必须写在双引号中。将它更改为if test= take way= 1 或if test=takeWay==1 。tostring()
.xml文件的部分代码
insert id=insertDelivery 参数type= com . zuci . request . deliverypreferencereq insert CX _ customer _ delivery preference trim prefix=( suffix=)suffix overrides=,.如果这里省略了test=takeWay==1 和workday!=null 工作日,/if./trim trim前缀=值(后缀=) su
ffixOverrides=","> .... 此处省略 <if test="takeWay == 1 and workday != null "> #{workday, jdbcType=VARCHAR}, </if> .... </trim></insert>takeWay == 1处出错,导致不执行if判断中的sql,运行程序不报错,没有任何提示。去掉takeWay == 1 and 则可执行。对此我百思不得其解,
因为自己有写过如下代码,是没错的。
<if test="messageType == senderReceiveSuccess "> ......</if>
把<if test="takeWay == '1' and workday != null ">改为<if test='takeWay == "1" and workday != null '>或改为<if test="takeWay == '1'.toString() and workday != null ">即可。原因是:mybatis是用OGNL表达式来解析的,在OGNL的表达式中,’1’会被解析成字符,java是强类型的,char 和 一个string 会导致不等,所以if标签中的sql不会被解析。
总结下使用方法:单个的字符要写到双引号里面或者使用.toString()才行!
使用Mybatis时,常常会判断属性是否为空
POJO
private Integer status;//状态,可能为0、1、2、3。
Mapper XML
<sql> <trim prefix="where" prefixOverrides="and or "> //...省略其他 <if test="status != null and status !=">and status = #{status}</if> <trim prefix="where" prefixOverrides="and or "></sql>
当status的值为 0时该where SQL and status = 0并未正常拼接,也就是说test内的表达式为false,从而导致查询结果错误。但是,显然该值(Integer :0)!= null也!= ' ',应该为true才对。当status为Integer类型,并且status值为0时,该if判断却为false。当status为0时,Mybatis会解析成'' 空字符串。为了避免这个问题,改成下面这样写,去掉对空字符的判断,就解决了该问题
<if test="status != null">and status = #{status}</if>
原因分析
通过Debug MyBatis源码顺藤摸瓜找到了IfSqlNode类,该类用来处理动态SQL的<if>节点,方法public boolean apply(DynamicContext context)用来构造节点内的SQL语句。if (evaluator.evaluateBoolean(test, context.getBindings())该代码便是解析<if test="status !=null and status !=''">test内表达式的关键,如果表达式为true则拼接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<String, ognl.Node> expressionCache = new ConcurrentHashMap<String, ognl.Node>(); 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)).topLevelExpression(); 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 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.
果然,如果对象是一个Number类型,值为0时将被解析为false,否则为true,浮点型0.00也是如此。OGNL对于boolean的定义和JavaScript有点像,即'' == 0 == false。这也就不难理解<if test="status != null and status !=''">and status = #{status}</if>当status=0时出现的问题了,显然0!=''是不成立的,导致表达式的值为false。
将表达式修改为<if test="status != null">and status = #{status}</if>该问题便迎刃而解。该问题的根源还是来自编码的不规范,只有String类型才需要判断是否!='',其他类型完全没有这个必要,可能是开发人员为了省事直接复制上一行拿过来改一改或是所使用的MyBatis生成工具不严谨导致该问题的发生。
这里有必要再提一个坑,如果你有类似于String str ="A"; <if test="str!= null and str == 'A'">这样的写法时,你要小心了。因为单引号内如果为单个字符时,OGNL将会识别为Java 中的 char类型,显然String 类型与char类型做==运算会返回false,从而导致表达式不成立。解决方法很简单,修改为<if test='str!= null and str == "A"'>即可。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持盛行IT。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。