直到你进入到DynamicContext.java类时
public DynamicContext(Configuration configuration, Object parameterObject) { if (parameterObject != null && !(parameterObject instanceof Map)) { MetaObject metaObject = configuration.newMetaObject(parameterObject); bindings = new ContextMap(metaObject); } else { bindings = new ContextMap(null); } bindings.put(PARAMETER_OBJECT_KEY, parameterObject); bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId()); }
此时,你不妨wait a moment,翻看一下该类的整体代码,你会发现:
public static final String PARAMETER_OBJECT_KEY = "_parameter";
public static final String DATABASE_ID_KEY = "_databaseId";
1
2
这里有两个常量,当然了,但看此处,也许你会发现"_parameter"这个关键字,但这时还说明不了什么,你且记住bindings.put(PARAMETER_OBJECT_KEY, parameterObject);,同时对ContextMap bindings对象留有一点印象。
key1:_parameter
(…)(省略步骤,个人调试过程中请注意。)
然后,我们进入MixedSqlNode.java
public boolean apply(DynamicContext context) {
for (SqlNode sqlNode : contents) {
sqlNode.apply(context);
}
return true;
}
该apply方法就非常有意思了,xml里配置的sql语句,会通过该方法转换为标准的sql(称之为标准,是值这形成的sql语句就是能够执行预处理sql查询的字符串),你不妨慢一点执行该循环语句。
第二次循环的时候,你就可以看到sql的雏形了,那么请继续。
(…)(省略步骤,个人调试过程中请注意。)
直到你发现,sqlNode的类型为ChooseSqlNode,此时,你是否已经能联想到以下内容:
<choose>
<when test="_parameter != null">
1
2
事情开始变得明朗起来,真好。
(…)(省略步骤,个人调试过程中请注意。)
继续调试,直到你进入到ExpressionEvaluator.java
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;
}
1
2
3
4
5
6
expression的值为username != null
parameterObject的值为{_parameter=00010001, _databaseId=null}
以上两个参数之间好像有点关系,但离源泉处还差那么几步,请继续。
紧接着,我们进入到OgnlCache.java
public static Object getValue(String expression, Object root) { try { return Ognl.getValue(parseExpression(expression), root); } catch (OgnlException e) { throw new BuilderException("Error evaluating expression '" + expression + "'. Cause: " + e, e); } }
进入到OgnlCache.java
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); } }
key2:
parseExpression(expression)的类型为Node,其值为username != null。
root的类型为DynamicContext$ContextMap (id=41),其值为{_parameter=00010001, _databaseId=null}
(…)(省略步骤,个人调试过程中请注意。)
当再继续执行的话,就回到了DefaultSqlSession.java
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { MappedStatement ms = configuration.getMappedStatement(statement); List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); return result; } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
此时错误已经抛出了,见下图
到了这,异常是找到怎么抛出了,但整体看上来,好像又缺点什么,没错,由于eclipse中无法再看到Ognl.getValue(parseExpression(expression), root);,所以就会造成困扰,我们通过反编译工具,可以看到getValue方法。
public static Object getValue(Object tree, Object root) throws OgnlException { return getValue(tree, root, null); }
public static Object getValue(Object tree, Map context, Object root) throws OgnlException { return getValue(tree, context, root, 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, null, null, result, resultType); } return result; }
此时再结合key2给出的内容,我们可以知道,要在{_parameter=00010001, _databaseId=null}匹配到porperty为username的值是不可能的啦,这样的话,程序就会抛出org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'username' in 'class java.lang.String'错误了!
最近,有不少读者问我是怎么学习的,那我干脆就把我看过的一些优质书籍贡献出来:
计算机基础入门推荐:《程序是怎样跑起来的》、《网络是怎样连接的》、《计算机是怎样跑起来的的》
进一步认识计算机网络:《计算机网络:自顶向下》、《图解http》
数据结构+算法入门:《大话数据结构》、《阿哈算法》
算法进阶:《算法第四版》、《编程珠玑》
由于我是 Java 技术栈的,顺便推荐几本 Java 的书籍,从左到由的顺序看到
Java:《Java核心技术卷1》、《编程思想》、《深入理解Java虚拟机》、《effective Java》、《Java并发编程的艺术》
数据库:《mysql必知必会》、《MySQL技术内幕:InnoDB存储引擎》
就先介绍这么多,这些都是最基础最核心的,希望对那些不知道看什么书的同学有所帮助。