需求: 有四个sql 都需要用一个 相同的where 条件,于是定义了一个sql 标签。 然后在每个sql中使用

<include refid="myWhereSql"></include> 引入。

后来需求变更,有两个sql 的where条件有一个参数需要和其他两个不同。 于是想到了bind标签

sql 3 : <bind name = "req.cc"  value="1">

sql 4 : <bind name = "req.cc"  value="2">

List<O1> m1(@Param("req") CRequest req);  cc 为 CRequest 中的一个 属性。

这样在sql3 和 sql4 中 cc的参数就可以 不同了 。

<if test="req.cc!= null and req.cc!= ''">
and t.col1= #{req.cc}
</if>
<if test="req.dd!= null and req.dd!= ''">
and t.col2 = #{req.dd}
</if>

发现 #{req.cc} 是能正确取到值的。 于是以为解决问题了。 然而后来发现 参数dd我 传值了,但是 #{req.dd} 却取不到。

研究源码发现: MybatisDefaultParameterHandler.setParameters

                    if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {

重点是 hasAdditionalParameter 方法:

public boolean hasAdditionalParameter(String name) {
String paramName = new PropertyTokenizer(name).getName();
return additionalParameters.containsKey(paramName);
}
PropertyTokenizer 解析后的getName 返回是req (说明是按照.分割的)。 
所有req.cc 和 req.dd 都是 走这个 if 分支去获取value 值的。
value = boundSql.getAdditionalParameter(propertyName);

这里调试代码发现mybatis 会把参数生成两个map , 一个是 方法传递的参数,名称为 _paramters , 一个是额外的参数,比如bind的 名字是 req (本例) 。

这就导致 cc 和  dd 都去 从这个 名称为req的map 中获取,所以dd 是没有值的。

看来这就是一个前缀取法的坑,对于复杂对象,优先去前缀。由于先取前缀, 本来只是想覆盖其中一个属性的,这样一来,等于前缀下的所有属性都被覆盖了。 

那么如果我直接写 <bind name="cc" value = "1" > , debug 发现 他会 往 additionalParameters(注意他也是一个map) 中添加一个 key 为 cc 的 键。所以也不行。

想到一个解决方案: 既然是map , 那么能不能这样呢 ?

<bind name="_parameter.param1.cc" value="1"></bind> debug发现 cc 能取到覆盖后的值, dd 也能正常取值了。 

但是新的问题却出现了:

<if test="req.cc!= null and req.cc!= ''">
and t.col1= #{req.cc}
</if>

我把cc 设置为 null, 发现 if 判断并没有其作用。debug代码在 MybatisCachingExecutor.query 方法,然后调用MappedStatement.getBoundSql 生成 BoundSql 。其会根据 bind 标签配置 和 方法参数 共同解析生成sql 语句。

DynamicContext context = new DynamicContext(configuration, parameterObject);
rootSqlNode.apply(context);

if 判断会调用 IfSqlNode.apply() , 该方法会解析if表达式,

这里发现bind的 参数 名称尽然是 _parameter.req.cc ,而不是像处理参数那样覆盖_parameter这个map里面的req参数值。

根据这个方法,其最终会找到 _parameter中找到req , 在req中找到 cc。  这个cc 是我方法请求参数,并没有被覆盖 , 显然不是null。

结论: mybatis xml 中 if 判断  和  取值(如#{cc})使用的参数处理机制不同,导致取值能覆盖,但是if 判断不会覆盖。这算不算bug。

结论:

1. 不能用bind 覆盖复杂对象的的某个属性。

2. 为避免bug,不建议使用覆盖。建议定义新的参数名,避免有坑。

最新文章

  1. 详解Jquery和AngularJs,Servlet中jsonp解决跨域问题(转)
  2. Kettle使用jndi mssqlserver
  3. Linux 双线策略路由的三种实现方式总结+端口映射
  4. leetcode@ [316] Remove Duplicate Letters (Stack &amp; Greedy)
  5. poj 3250 Bad Hair Day【栈】
  6. hdu 2079 选课时间
  7. 张孝祥Java高新技术汇总
  8. jQuery 复制节点的元素实现加入到购物车功能
  9. 房费制VB版本(一个)——系统分析
  10. 解决cookie 跨iframe
  11. ROS分布式控制的节点配置
  12. [Leetcode221]最大面积 Maximal Square
  13. ant design Modal关闭时清除数据的解决方案
  14. lua脚本之lua语言简介以及lua的安装
  15. Selenium 执行JavaScript
  16. XML 实体
  17. SDN 第一次作业
  18. 【读书笔记】《Computer Organization and Design: The Hardware/Software Interface》(1)
  19. VS2010+WinXP+MFC程序 无法定位程序输入点于动态链接库
  20. var 是 Java 开发的好朋友啊!

热门文章

  1. 打卡ts day02--使用typescript 写评论demo
  2. 在docker中导入python的包时ImportError: libgthread-2.0.so.0: cannot open shared object file: No such file or directory
  3. python使用pysimplegui简单制作一个exe程序
  4. span&amp;不同字体
  5. 题解[LuoguP6222]「P6156简单题」加强版
  6. 如何将视频作为Windows桌面动态壁纸,两步就可以搞定!
  7. linux端口探测
  8. Python3.6多线程爬虫
  9. gulp安装出错
  10. .Net最小工作线程对应用程序性能的影响