[转]mybatis if test非空判断数字0为什么是false
原文地址:http://blog.51cto.com/wangguangshuo/1944531
今天工作中发现一个Long类型的参数没有传到sql中去,在sql xml配置文件中是使用if test标签判断:
<if test="version != null and version != ''">xxxxx</if>
通过debug发现参数中的version是有值的,但出来的sql语句就没有这个version
网上查了一些有不少同样这样的问题,大致解决办法分两种:
1、去掉空字符串判断
<if test="version != null">xxxxx</if>
2、添加0值判断
<if test="version != null and version != '' or version == 0">xxxxx</if>
这两种方法都是可以的,在我看来是这样,如果这个version类型和我的情况一样,是包装类型而不是基本数据类型的话,第一种就足够了,而且更贴近实际,因为包装类型除了有值的情况就是null,不会为""空字符串的,String类型不在我讨论的范围内,标题已经说了是数字0,况且如果是String的话就不会有这个问题了。
知道了怎么解决这个问题,那就想知道为什么这个问题会出现,当然要查看mybatis的源码了,
sql语句是通过获取BoundSql来的(网上查看mybatis层次结构),这个是通过方法getBoundSql(),这个方法定义在一个接口SqlSource,它有五个实现,从命名上看应该是找DynamicSqlSource,
<img/>暂时缺少图片
if判断的这种属于动态的sql所以直接找它了
这里面有句:rootSqlNode.apply(content);这个是添加动态sql 的,点进去查看
apply也是在一个接口里,查看实现,各种和标签有关的命名实现,这个标签是if当然就是找IfSqlNode了,它里面的实现是通过evaluator.evaluateBoolean()方法判断的,点进去继续看
发现一行重要的代码:
if(value instanceof Number) return !new BigDecimal(String.valueOf(value)).equals(BigDecimal.ZERO);
现在真相大白了,不管是Inteter还是Long,只要是值为0,都会判断为false
真的很抱歉,上面的分析错了,早上来了之后有四个浏览,立刻隐藏了这篇文章准备修改,希望那四位网友能再看到更正,上面的分析是在昨天晚上下班后,现在我又看了一遍昨天打开的源码:
上面的value其实是test后面的表达式的返回值,而不是传入的version参数,test后面的表达式如果只写一个0的话就会走上面的if判断,直接返回false,但眼前的情况是version为0,test后面的表达式就是:0 != null and 0 != '',这个表达式是由org.apache.ibatis.scripting.xmltags.OgnlCache类的getValue(String expression,Objec root)方法得来,下载了ognl源码包关联之后从新走的debug追踪了一下,还是从上面IfSqlNode中的apply方法判断说起:
(DynamicContext context) {
(.evaluateBoolean(context.getBindings())) {
.apply(context)}
}
进入evaluateBoolean方法:
(String expressionObject parameterObject) {
Object value = OgnlCache.(expressionparameterObject)(value Boolean) (Boolean) value(value Number) !BigDecimal(String.(value)).equals(BigDecimal.)value != }
这里面expression参数就是“version != null and version != ''”这个getValue方法里面就是调用Ognl包中的方法处理之后返回的一个值,进去这个getValue方法中
Object (String expressionObject root) {
{
Map<ObjectOgnlCla***esolver> context = Ognl.(rootOgnlCla***esolver())Ognl.((expression)contextroot)} (OgnlException e) {
BuilderException(+ expression + + ee)}
}
这里面parseExpression(expression)是解析表达式的,没有决定到最终结果,还是要进去看getvalue方法,里面调用了好多层,debug下一步一步进去追踪,会发现下面的关键代码:
Object getValueBody(OgnlContext contextObject source) OgnlException {
Object v1 = .children[].getValue(contextsource)Object v2 = .children[].getValue(contextsource)OgnlOps.equal(v1v2)?Boolean.FALSE:Boolean.TRUE}
上面的表达式是version != null and version != '',这个方法是在一个for循环里调用的,分别是0和null的比较,0和""的比较,第一次比较肯定是true不用说了,第二次的时候v1就是0,v2就是"",继续查看这里的OgnlOps.equal()方法
equal(Object v1Object v2) {
v1 == ?v2 == :(v1 != v2 && !isEqual(v1v2)?(v1 Number && v2 Number?((Number)v1).doubleValue() == ((Number)v2).doubleValue():):)}
0和null判断为false,执行:后面的,关键取决于isEqual()方法了,进去这方法里又能看到一个方法
result = compareWithConversion(object1, object2, true) == 0 || object1.equals(object2);
进去查看
compareWithConversion(Object v1Object v2equals) {
result(v1 == v2) {
result = } {
t1 = getNumericType(v1)t2 = getNumericType(v2)type = getNumericType(t1t2)(type) {
:
result = bigIntValue(v1).compareTo(bigIntValue(v2)):
result = bigDecValue(v1).compareTo(bigDecValue(v2)):
(t1 == && t2 == ) {
(v1 != && v2 != ) {
(v1.getClass().isAssignableFrom(v2.getClass()) || v2.getClass().isAssignableFrom(v1.getClass())) {
(v1 Comparable) {
result = ((Comparable)v1).compareTo(v2)}
(equals) {
result = v1.equals(v2)?:}
}
(!equals) {
IllegalArgumentException(+ v1.getClass().getName() + + v2.getClass().getName())}
result = } {
var10000 = v1 != v2}
}
:
:
dv1 = doubleValue(v1)dv2 = doubleValue(v2)dv1 == dv2?:(dv1 < dv2?-:):
lv1 = longValue(v1)lv2 = longValue(v2)lv1 == lv2?:(lv1 < lv2?-:)}
}
result}
参数一个是0,一个是"",最终debug会走进case 8 里面,0和“”都会被转成double进行比较,都会变成0.0,这就是mybati中if test 0!=""判定为false的原因
[转]mybatis if test非空判断数字0为什么是false的更多相关文章
- Mybatis基本类型参数非空判断(异常:There is no getter for property...)
先看一小段代码 <select id="queryByPhone" parameterType="java.lang.String" resultType ...
- java基础之----非空判断
大家好,第一次写博客,一直想写博客,用于自我总结,也用于帮助新同学成长. 平常我们开发的时候,用到很多非空判断,但是很多同学用到的地方不是很准确,这里,我把自己平时遇到的坑跟大家说说.我废话不多,只想 ...
- C/C++ 指针的非空判断
一定要分得清楚C和C++的“空指针常量”不是一样的.C标准不保证NULL等于0,所以做指针非空判断时,应该用if(p != NULL):因为“上下文转换到bool值”的统一性,C++就应该用if(p) ...
- JAVAWEB servlet验证登录时进行完全的非空判断防止空值登录
如果不进行完全的非空判断,那么对 "" 这种类型的空值就会导致直接登录 所以需要用下面的字符串处理方法对其进行判断 这样就可以防止空值登录了 容易出现的混淆错误: 这里的空值登录容 ...
- String的非空判断、Integer的非空判断、list的大小判断,对象的非空判断
1.String的非空判断. StringUtils.isNotEmpty(String str); 2.Integer的非空判断. null != Integer ; 3.list的大小判断. li ...
- java8 Optional优雅非空判断
java8 Optional优雅非空判断 import java.util.ArrayList;import java.util.List;import java.util.Optional; pub ...
- python字符串非空判断
1. 字符串非空判断 2. list 非空判断
- proto3 不支持内建类型的非空判断即 hasXXX
proto3 移除了内建类型的非空判断方法 即代码生成工具不会为 bool int 等类型生成has方法 有使用过proto2 或者其它rpc 框架的人都知道使用has 方法去判断消息里的值是否设置, ...
- List和String的非空判断
1.如果想判断list是否为空,可以这么判断: if(null == list || list.size() ==0 ){ //为空的情况 }else{ //不为空的情况 } 2.list.isEmp ...
随机推荐
- IDEA使用笔记(三)——小齿轮的显示和隐藏(Autoscroll from Source)
在玩快捷键的时候,不清楚自己操作了什么,突然间发现——能直接定位到当前可编辑文件的哪个小齿轮,不见了,找了一会也没弄出来,从网上搜索吧!也没看到对应的方法,后来自己耐下心来复盘自己的操作,终于发现了, ...
- 你的应用是怎样被替换的,App劫持病毒剖析
一.App劫持病毒介绍 App劫持是指运行流程被重定向,又可分为Activity劫持.安装劫持.流量劫持.函数运行劫持等. 本文将对最近利用Acticity劫持和安装劫持的病毒进行分析. 二.Acti ...
- 小而美的ghost driver
做过selenium自动化项目的同学应该都遇到过这样的问题:测试用例太多,运行速度过慢导致团队成员怨声载道. 于是便有了selenium grid和多线程运行selenium测试用例的方法.这些方法各 ...
- MySQL设置从库只读模式
常见现象 运维工作中会经常维护MySQL主从服务器,当然Slave我们只是用于读操作. 一般权限开通也只授权只读账号,但是有时候维护工作可能不是一个人在做,你不能保证其他同事都按照这个标准操作. 有同 ...
- JQuery Tree插件——zTree
Demo:点击下载 zTree 在线操作演示:http://www.ztree.me/v3/demo.php#_101
- django -- 联合索引
一.定义: from django.db import models # Create your models here. class Person(models.Model): first_name ...
- 使用Talend Open Studio将数据分步从oracle导入到hive中
先使用Tos建立模型,将Oracle中的数据导入到本地: build job后,形成独立可以运行的程序: 将生成的zip文件,上传到hadoop集群上,有hive环境的机器上: [hive@h1 wo ...
- node 的安装
安装方法来自于 https://nodejs.org/en/download/package-manager/ Installing Node.js via package manager Note: ...
- HDU 1019 Least Common Multiple 数学题解
求一组数据的最小公倍数. 先求公约数在求公倍数.利用公倍数,连续求全部数的公倍数就能够了. #include <stdio.h> int GCD(int a, int b) { retur ...
- bestcoder 48# wyh2000 and a string problem (水题)
wyh2000 and a string problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K ...