• mybatis----Integer = 0 刷选不出来条件原因以及sql改法


    Xml写法:

     POJO:

    status的值为 0时该where SQLand status = 0并未正常拼接,也就是说test内的表达式为false,从而导致查询结果错误。但是,显然该值(Integer :0)!= null也!= ' ',应该为true才对。

    通过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:

    1. If the object is a Boolean, its value is extracted and returned;
    2. 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;
    3. If the object is a Character, its boolean value is true if and only if its char value is non-zero;
    4. 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"'>

    转载:https://www.jianshu.com/p/91ed365c0fdd
  • 相关阅读:
    .net Thrift 之旅 (一) Windows 安装及 HelloWorld
    软件测试中的过度设计
    血型和测试
    功能点算法及在软件测试中的应用Part2
    尘归尘 土归土
    解读SAO文化中的Share
    使用C#开发winform程序的界面框架
    怎样才能说明软件测试工作做的好?
    功能点算法及在软件测试中的应用Part1
    软件测试的核心价值是什么?
  • 原文地址:https://www.cnblogs.com/yw-ah/p/9933464.html
Copyright © 2020-2023  润新知