内容简介:在我们开发过程中用Mapper如下XMl中的sql如下
Mybatis解析判断表达式源码分析
在我们开发过程中用 Mybatis
经常会用到下面的例子
Mapper如下
Map<String ,String > testArray(@Param("array") String [] array);
XMl中的 sql 如下
<select id="testArray" resultType="map"> select * from t_ams_ac_pmt_dtl where cpt_pro=#{cptProp} <if test="array!=null and array != '' "> and cpt_pro=#{cptProp} </if> </select>
刚看上面的代码会觉得数组怎么能和空字符串进行一起比较呢,一开始会觉得这个代码运行起来绝对报错,但是写单元测试运行了一遍发现成功运行了。因此想是不是 Mybatis
在内部对数组类型的数据进行了封装。于是有了这一次的源码解析之旅。上网查了查发现 Mybatis
解析使用了 OGNL
。至于什么是 OGNL
摘抄了百度百科中的一段话
OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。这样可以更好的取得数据。
单元测试类如下
@Test public void testArray(){ SqlSession sqlSession = sqlSessionFactory.openSession(); TBapCheckPtsTranscdMapper mapper = sqlSession.getMapper(TBapCheckPtsTranscdMapper.class); String str= "1,2,3"; String [] strings = str.split(","); mapper.testArray(strings); }
首先我们先来看一下 DynamicSqlSource
这个类,这个类中有个方法如下
@Override public BoundSql getBoundSql(Object parameterObject) { DynamicContext context = new DynamicContext(configuration, parameterObject); rootSqlNode.apply(context); SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings()); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) { boundSql.setAdditionalParameter(entry.getKey(), entry.getValue()); } return boundSql; }
其中
rootSqlNode.apply(context);
这段代码对SQL进行了动态的拼接,然后点进去看一下
@Override public boolean apply(DynamicContext context) { for (SqlNode sqlNode : contents) { sqlNode.apply(context); } return true; }
这里的SQL拼接运用了 组合模式 不同的 sqlNode
调用的方法不一样,但是最后的想要结果都是一样的:拼接SQL。例如我们第一次进 apply
这个方法中的时候他跳转到了
StaticTextSqlNode
这个类中调用了下面的方法
@Override public boolean apply(DynamicContext context) { context.appendSql(text); return true; }
直接将SQL拼接为
select * from t_ams_ac_pmt_dtl where cpt_pro=#{cptProp}
然后我们第二次循环执行发现它跳转到了 IfSqlNode
这个类中,这是标签为 <if>
的判断类,
@Override public boolean apply(DynamicContext context) { if (evaluator.evaluateBoolean(test, context.getBindings())) { contents.apply(context); return true; } return false; }
在解析语句中传了两个参数进去
evaluator.evaluateBoolean(test, context.getBindings())
-
test
:就是要解析的表达式,在此场景下就是array!=null and array != ''
-
context.getBindings()
:获得的是一个Map,其中存储了参数array
的所对应的值,如下所示
image
然后接下来就到了 OGNL
解析表达式了,发现最后到了 ASTNotEq
这类中
protected Object getValueBody(OgnlContext context, Object source) throws OgnlException { Object v1 = this._children[0].getValue(context, source); Object v2 = this._children[1].getValue(context, source); return OgnlOps.equal(v1, v2) ? Boolean.FALSE : Boolean.TRUE; }
这里解析分为了两步进行解析,上面的表达式为 array!=null and array != ''
那么他会根据and 进行分组将其放入 Node
数组中。
-
Node[0]
:array!=null
-
Node[1]
:array != ''
然后这里面的两个参数 v1
和 v2
分别为左边和右边的参数,此时先解析 Node[0]
中的参数
-
v1
:就是参数array
对应的数组的值 -
v2
:就是null
此时到这应该就知道为什么 String
数组为什么能和空字符串进行比较了,因为他将数组转化为了 Object
然后用自己写的 equal
方法进行比较。然后进去他写的 equal
方法中看了以后发现他对数组比较是特殊的。
- 如果左边是数组右边是字符串:两个都转换为
Object
然后进行v1.getClass()==v2.getClass()
判断 - 如果左边是数组右边也是数组:先判断两个数组的长度是否相同,如果相同,那么循环遍历两个数组进行里面的值的比较
以上所述就是小编给大家介绍的《不学无数——Mybatis解析判断表达式源码分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 深入理解 lambda表达式 与 函数式编程 函数式接口源码解析(二)
- Spring Security源码分析十三:Spring Security 基于表达式的权限控制
- 正则表达式 – 如何使用正则表达式进行Erlang模式匹配?
- lambda表达式
- 表达式 / 语句
- Python正则表达式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Open Data Structures
Pat Morin / AU Press / 2013-6 / USD 29.66
Offered as an introduction to the field of data structures and algorithms, Open Data Structures covers the implementation and analysis of data structures for sequences (lists), queues, priority queues......一起来看看 《Open Data Structures》 这本书的介绍吧!