热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Mybatisif判断Integer类型的值不等于''引发的问题(!=''等价于!=0)

案例当传入的person属性age的值为0时,mybatis预编译下面的语句会报错,因为预编译的sql为:updatepersonwhe

案例

当传入的person属性age的值为0时,mybatis预编译下面的语句会报错,因为预编译的sql为:update person where id = 1

update personage = #{age}where id = 1


为什么 if 条件判断没有通过?

通过源码了解到,mybatis在预编译sql时,使用OGNL表达式来解析if标签,对于Integer类型属性,在判断不等于''时,例如age != '',OGNL会返回''的长度,源码:(s.length() == 0) ? 0.0 : Double.parseDouble( s ),因此表达式age != ''被当做age != 0来判断,所以当age0时,if条件判断不通过。


总结


  1. 在设计实体类时,实体属性要使用基本数据类型的包装类型,因为基本数据类型有默认值
  2. if条件判断number类型,没必要判断''的情况,只需判断null的情况,如果非要判断''的情况,那么要考虑到等于0的情况,即

源码分析

mybatis调用OGNL源码的入口:


  1. age != ''表达式封装为ognl.Node,ognl.Node使用组合设计模式,Node分为普通节点,常量节点等类型的节点

  2. 调用OgnlgetValue静态方法,参数1:条件表达式封装的ognl.Node,参数2:Person对象(mybatis传入的是一个Map)

    这里写图片描述

调试OGNL的代码:

依赖:

ognlognl2.6.9

代码:

public static void main(String[] args) throws Exception {String expression = "age != ''";Node node = new OgnlParser(new StringReader(expression)).topLevelExpression();Person person = new Person();person.setAge(0);Object value = Ognl.getValue(node, person);System.out.println(value);
}

  1. 条件表达式判断入口,Ognl#getValue方法

    这里写图片描述

  2. Ognl#getValue重载方法,这个方法将参数tree强转为Node类型,它的实际类型是SimpleNode,并调用SimpleNode#getValue方法,SimpleNode中有Node[] children属性,OGNL使用组合设计模式,将age != ''分成ASTProperty封装的age属性节点和ASTConst封装的''常量节点,且age属性节点的children属性有一个ASTConst常量节点,它valueage的属性名称。ASTConst类型节点的children一般情况下为null,即此类节点一般没有子节点

    这里写图片描述

    这里写图片描述

  3. SimpleNode#getValue方法else分支调用了evaluateGetValueBody方法,此方法中调用ExpressionNode#isConstant方法,判断SimpleNodechildren是否全是常量节点(常量节点请参考SimleNode的子类),这里hasContantValuefalse,所以在执行return的三目运算时,调用ASTNotEq#getValueBody方法,因为我们的条件是不等于,所以我们应该查看ASTNotEq中的方法。

    这里写图片描述

    这里写图片描述

  4. ASTNotEq#getValueBody方法,SimpleNode中的children[0]age属性节点,children[1]''常量节点,这里分别获取节点的值。children[0]是属性节点,调用getValue方法,重复走第3步的操作,注意,此时调用的getValueBodyASTProperty的方法,获取age节点的常量节点,并从person类中提取age的值,而children[1]是常量节点,因此走第3步操作时,hasConstantValuetrue,直接返回constantValue,值为""。然后调用OgnlOps#equal方法,参数1:age的实际值,参数2:与age做判断的值''
    这里写图片描述

    这里写图片描述

    这里写图片描述

  5. OgnlOps#equal方法,在第二个if条件中,调用isEqual方法,isEqual最里层的else中调用的compareWithConversion方法,首先通过getNumericType方法获取到参数的真实类型,再通过getNumericType重载方法获取两个参数的最大类型(参见NumericTypes接口)这里返回NONNUMERIC,然后通过switch分支处理,由于参数1和参数2不都为NONNUMERIC,因此switch分支走DOUBLEcase,分别获取两个参数的Double值,对于参数2空字符串,在调用doubleValue方法时,先去掉左右空格,再取字符串长度作为最后的值,与age的值进行比较,即return (dv1 == dv2) ? 0 : ((dv1 ,dv1dv2都是0,然后回看result = (compareWithConversion(object1, object2, true) == 0) || object1.equals(object2);返回true,return OgnlOps.equal( v1, v2 )? Boolean.FALSE : Boolean.TRUE;返回false,最终返回false,条件不成立

    这里写图片描述

    这里写图片描述

    这里写图片描述

    这里写图片描述

    这里写图片描述

    这里写图片描述

    这里写图片描述


推荐阅读
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • Commit1ced2a7433ea8937a1b260ea65d708f32ca7c95eintroduceda+Clonetraitboundtom ... [详细]
  • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 本文介绍了在Go语言中可见性与scope的规则,包括在函数内外声明的可见性、命名规范和命名风格,以及变量声明和短变量声明的语法。同时,还介绍了变量的生命周期,包括包级别变量和局部变量的生命周期,以及变量在堆和栈上分配的规则和逃逸分析的概念。 ... [详细]
  • 判断编码是否可立即解码的程序及电话号码一致性判断程序
    本文介绍了两个编程题目,一个是判断编码是否可立即解码的程序,另一个是判断电话号码一致性的程序。对于第一个题目,给出一组二进制编码,判断是否存在一个编码是另一个编码的前缀,如果不存在则称为可立即解码的编码。对于第二个题目,给出一些电话号码,判断是否存在一个号码是另一个号码的前缀,如果不存在则说明这些号码是一致的。两个题目的解法类似,都使用了树的数据结构来实现。 ... [详细]
  • WPF之Binding初探
      初学wpf,经常被Binding搞晕,以下记录写Binding的基础。首先,盗用张图。这图形象的说明了Binding的机理。对于Binding,意思是数据绑定,基本用法是:1、 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 本文介绍了如何清除Eclipse中SVN用户的设置。首先需要查看使用的SVN接口,然后根据接口类型找到相应的目录并删除相关文件。最后使用SVN更新或提交来应用更改。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
author-avatar
yo繽紛樂
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有