博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一次Mybatis sql解析故障分析
阅读量:6311 次
发布时间:2019-06-22

本文共 14779 字,大约阅读时间需要 49 分钟。

hot3.png

现象

在测试中发现,以上sql在mybatis解析后,sortord无论是"0"或者"1"单个字符串,都会倒序执行。

源码分析原因

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.apache.ibatis.scripting.xmltags;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 (this.evaluator.evaluateBoolean(this.test, context.getBindings())) {            this.contents.apply(context);            return true;        } else {            return false;        }    }}

sql节点调用apply方法中this.evaluator.evaluateBoolean方法

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.apache.ibatis.scripting.xmltags;import java.lang.reflect.Array;import java.math.BigDecimal;import java.util.ArrayList;import java.util.List;import java.util.Map;import org.apache.ibatis.builder.BuilderException;public class ExpressionEvaluator {    public ExpressionEvaluator() {    }    public boolean evaluateBoolean(String expression, Object parameterObject) {        Object value = OgnlCache.getValue(expression, parameterObject);        if (value instanceof Boolean) {            return (Boolean)value;        } else if (value instanceof Number) {            return !(new BigDecimal(String.valueOf(value))).equals(BigDecimal.ZERO);        } else {            return value != null;        }    }    public Iterable
evaluateIterable(String expression, Object parameterObject) { Object value = OgnlCache.getValue(expression, parameterObject); if (value == null) { throw new BuilderException("The expression '" + expression + "' evaluated to a null value."); } else if (value instanceof Iterable) { return (Iterable)value; } else if (!value.getClass().isArray()) { if (value instanceof Map) { return ((Map)value).entrySet(); } else { throw new BuilderException("Error evaluating expression '" + expression + "'. Return value (" + value + ") was not iterable."); } } else { int size = Array.getLength(value); List answer = new ArrayList(); for(int i = 0; i < size; ++i) { Object o = Array.get(value, i); answer.add(o); } return answer; } }}

Object value = OgnlCache.getValue(expression, parameterObject);行使用ognl方式获取test中表达式test='sortord!="0"'的值

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.apache.ibatis.scripting.xmltags;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import org.apache.ibatis.builder.BuilderException;import org.apache.ibatis.ognl.Ognl;import org.apache.ibatis.ognl.OgnlException;public final class OgnlCache {    private static final Map
expressionCache = new ConcurrentHashMap(); private OgnlCache() { } public static Object getValue(String expression, Object root) { try { Map
context = Ognl.createDefaultContext(root, new OgnlClassResolver()); return Ognl.getValue(parseExpression(expression), context, root); } catch (OgnlException var3) { throw new BuilderException("Error evaluating expression '" + expression + "'. Cause: " + var3, var3); } } private static Object parseExpression(String expression) throws OgnlException { Object node = expressionCache.get(expression); if (node == null) { node = Ognl.parseExpression(expression); expressionCache.put(expression, node); } return node; }}
package org.apache.ibatis.ognl;import java.io.StringReader;import java.lang.reflect.Member;import java.util.Map;public abstract class Ognl {    public static Object parseExpression(String expression) throws OgnlException {        try {            OgnlParser parser = new OgnlParser(new StringReader(expression));            return parser.topLevelExpression();        } catch (ParseException var2) {            throw new ExpressionSyntaxException(expression, var2);        } catch (TokenMgrError var3) {            throw new ExpressionSyntaxException(expression, var3);        }    }    public static Map createDefaultContext(Object root) {        return addDefaultContext(root, (ClassResolver)null, (TypeConverter)null, (MemberAccess)null, new OgnlContext());    }    public static Map createDefaultContext(Object root, ClassResolver classResolver) {        return addDefaultContext(root, classResolver, (TypeConverter)null, (MemberAccess)null, new OgnlContext());    }    public static Map createDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter) {        return addDefaultContext(root, classResolver, converter, (MemberAccess)null, new OgnlContext());    }    public static Map createDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess) {        return addDefaultContext(root, classResolver, converter, memberAccess, new OgnlContext());    }    public static Map addDefaultContext(Object root, Map context) {        return addDefaultContext(root, (ClassResolver)null, (TypeConverter)null, (MemberAccess)null, context);    }    public static Map addDefaultContext(Object root, ClassResolver classResolver, Map context) {        return addDefaultContext(root, classResolver, (TypeConverter)null, (MemberAccess)null, context);    }    public static Map addDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter, Map context) {        return addDefaultContext(root, classResolver, converter, (MemberAccess)null, context);    }    public static Map addDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess, Map context) {        OgnlContext result;        if (!(context instanceof OgnlContext)) {            result = new OgnlContext();            result.setValues(context);        } else {            result = (OgnlContext)context;        }        if (classResolver != null) {            result.setClassResolver(classResolver);        }        if (converter != null) {            result.setTypeConverter(converter);        }        if (memberAccess != null) {            result.setMemberAccess(memberAccess);        }        result.setRoot(root);        return result;    }    public static void setClassResolver(Map context, ClassResolver classResolver) {        context.put("_classResolver", classResolver);    }    public static ClassResolver getClassResolver(Map context) {        return (ClassResolver)context.get("_classResolver");    }    public static void setTypeConverter(Map context, TypeConverter converter) {        context.put("_typeConverter", converter);    }    public static TypeConverter getTypeConverter(Map context) {        return (TypeConverter)context.get("_typeConverter");    }    public static void setMemberAccess(Map context, MemberAccess memberAccess) {        context.put("_memberAccess", memberAccess);    }    public static MemberAccess getMemberAccess(Map context) {        return (MemberAccess)context.get("_memberAccess");    }    public static void setRoot(Map context, Object root) {        context.put("root", root);    }    public static Object getRoot(Map context) {        return context.get("root");    }    public static Evaluation getLastEvaluation(Map context) {        return (Evaluation)context.get("_lastEvaluation");    }    public static Object getValue(Object tree, Map context, Object root) throws OgnlException {        return getValue((Object)tree, context, root, (Class)null);    }    public static Object getValue(Object tree, Map context, Object root, Class resultType) throws OgnlException {        OgnlContext ognlContext = (OgnlContext)addDefaultContext(root, context);        Object result = ((Node)tree).getValue(ognlContext, root);        if (resultType != null) {            result = getTypeConverter(context).convertValue(context, root, (Member)null, (String)null, result, resultType);        }        return result;    }    public static Object getValue(String expression, Map context, Object root) throws OgnlException {        return getValue((String)expression, context, root, (Class)null);    }    public static Object getValue(String expression, Map context, Object root, Class resultType) throws OgnlException {        return getValue(parseExpression(expression), context, root, resultType);    }    public static Object getValue(Object tree, Object root) throws OgnlException {        return getValue((Object)tree, (Object)root, (Class)null);    }    public static Object getValue(Object tree, Object root, Class resultType) throws OgnlException {        return getValue(tree, createDefaultContext(root), root, resultType);    }    public static Object getValue(String expression, Object root) throws OgnlException {        return getValue((String)expression, (Object)root, (Class)null);    }    public static Object getValue(String expression, Object root, Class resultType) throws OgnlException {        return getValue(parseExpression(expression), root, resultType);    }    public static void setValue(Object tree, Map context, Object root, Object value) throws OgnlException {        OgnlContext ognlContext = (OgnlContext)addDefaultContext(root, context);        Node n = (Node)tree;        n.setValue(ognlContext, root, value);    }    public static void setValue(String expression, Map context, Object root, Object value) throws OgnlException {        setValue(parseExpression(expression), context, root, value);    }    public static void setValue(Object tree, Object root, Object value) throws OgnlException {        setValue(tree, createDefaultContext(root), root, value);    }    public static void setValue(String expression, Object root, Object value) throws OgnlException {        setValue(parseExpression(expression), root, value);    }    public static boolean isConstant(Object tree, Map context) throws OgnlException {        return ((SimpleNode)tree).isConstant((OgnlContext)addDefaultContext((Object)null, context));    }    public static boolean isConstant(String expression, Map context) throws OgnlException {        return isConstant(parseExpression(expression), context);    }    public static boolean isConstant(Object tree) throws OgnlException {        return isConstant(tree, createDefaultContext((Object)null));    }    public static boolean isConstant(String expression) throws OgnlException {        return isConstant(parseExpression(expression), createDefaultContext((Object)null));    }    public static boolean isSimpleProperty(Object tree, Map context) throws OgnlException {        return ((SimpleNode)tree).isSimpleProperty((OgnlContext)addDefaultContext((Object)null, context));    }    public static boolean isSimpleProperty(String expression, Map context) throws OgnlException {        return isSimpleProperty(parseExpression(expression), context);    }    public static boolean isSimpleProperty(Object tree) throws OgnlException {        return isSimpleProperty(tree, createDefaultContext((Object)null));    }    public static boolean isSimpleProperty(String expression) throws OgnlException {        return isSimpleProperty(parseExpression(expression), createDefaultContext((Object)null));    }    public static boolean isSimpleNavigationChain(Object tree, Map context) throws OgnlException {        return ((SimpleNode)tree).isSimpleNavigationChain((OgnlContext)addDefaultContext((Object)null, context));    }    public static boolean isSimpleNavigationChain(String expression, Map context) throws OgnlException {        return isSimpleNavigationChain(parseExpression(expression), context);    }    public static boolean isSimpleNavigationChain(Object tree) throws OgnlException {        return isSimpleNavigationChain(tree, createDefaultContext((Object)null));    }    public static boolean isSimpleNavigationChain(String expression) throws OgnlException {        return isSimpleNavigationChain(parseExpression(expression), createDefaultContext((Object)null));    }    private Ognl() {    }}调用getValue方法获取表达式的值
package org.apache.ibatis.ognl;import java.lang.reflect.Member;import java.util.Map;public class DefaultTypeConverter implements TypeConverter {    public DefaultTypeConverter() {    }    public Object convertValue(Map context, Object value, Class toType) {        return OgnlOps.convertValue(value, toType);    }    public Object convertValue(Map context, Object target, Member member, String propertyName, Object value, Class toType) {        return this.convertValue(context, value, toType);    }}
protected Object evaluateGetValueBody(OgnlContext context, Object source) throws OgnlException {        context.setCurrentObject(source);        context.setCurrentNode(this);        if (!this.constantValueCalculated) {            this.constantValueCalculated = true;            this.hasConstantValue = this.isConstant(context);            if (this.hasConstantValue) {                this.constantValue = this.getValueBody(context, source);            }        }        return this.hasConstantValue ? this.constantValue : this.getValueBody(context, source);    }

以上getValueBody有多种AST开头的实现,如ASTList,ASTNotEq,ASTEq,ASTNotIn,ASTOr等,这里主要看ASTNotEq AST实现

package org.apache.ibatis.ognl;class ASTNotEq extends ExpressionNode {    public ASTNotEq(int id) {        super(id);    }    public ASTNotEq(OgnlParser p, int id) {        super(p, id);    }    protected Object getValueBody(OgnlContext context, Object source) throws OgnlException {        Object v1 = super.children[0].getValue(context, source);        Object v2 = super.children[1].getValue(context, source);        return OgnlOps.equal(v1, v2) ? Boolean.FALSE : Boolean.TRUE;    }    public String getExpressionOperator(int index) {        return "!=";    }}

当使用test="sorted !='0' "时,解析出结果如下 '0'被解析成Charactor字符类型

当使用test='sorted !="0"'时,'0'被解析成String字符串类型

当!=后面的值时''时,解析结果如下 即能解析出正确的结果

结论

变量与单个常量字符比较 需要使用test='sorted !="0"',变量与空字符常量比较,test="sorted !='0'"即可

转载于:https://my.oschina.net/odetteisgorgeous/blog/3010296

你可能感兴趣的文章
【python进阶】深入理解系统进程2
查看>>
Redis(十二):redis两种持久化方法对比分析
查看>>
Creating Python GUI Applications using XULRunner
查看>>
新时代的编辑力
查看>>
分布式事务 原理及使用范例一则
查看>>
程序员得到的报酬与他们的生产力不成正比
查看>>
x86 cpu内存管理
查看>>
Oracle Enterprise Manager Cloud Control 12c 概述
查看>>
Delphi中的线程类 - TThread详解<转>
查看>>
Linq 分组统计
查看>>
多种数据DELPHI备份方式(源码)
查看>>
丰富的jquery选择器
查看>>
深入探讨用位掩码代替分支(3):VC6速度测试
查看>>
4种方式从老客户那拿到新项目
查看>>
JQuery遮罩层登录
查看>>
采用oracle过程发邮件
查看>>
Date对象的一些相关函数
查看>>
使用Wireshark抓取SNMP Trap包
查看>>
IOS怎么设置View的背景会比较顺畅比较好的解决方法
查看>>
SOCKET是多线程安全的吗? [问题点数:40分,结帖人CSDN]
查看>>