mybatis bind 标签 覆盖 复杂对象的某个属性值 问题。
需求: 有四个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,不建议使用覆盖。建议定义新的参数名,避免有坑。
最新文章
- 详解Jquery和AngularJs,Servlet中jsonp解决跨域问题(转)
- Kettle使用jndi mssqlserver
- Linux 双线策略路由的三种实现方式总结+端口映射
- leetcode@ [316] Remove Duplicate Letters (Stack &; Greedy)
- poj 3250 Bad Hair Day【栈】
- hdu 2079 选课时间
- 张孝祥Java高新技术汇总
- jQuery 复制节点的元素实现加入到购物车功能
- 房费制VB版本(一个)——系统分析
- 解决cookie 跨iframe
- ROS分布式控制的节点配置
- [Leetcode221]最大面积 Maximal Square
- ant design Modal关闭时清除数据的解决方案
- lua脚本之lua语言简介以及lua的安装
- Selenium 执行JavaScript
- XML 实体
- SDN 第一次作业
- 【读书笔记】《Computer Organization and Design: The Hardware/Software Interface》(1)
- VS2010+WinXP+MFC程序 无法定位程序输入点于动态链接库
- var 是 Java 开发的好朋友啊!
热门文章
- 打卡ts day02--使用typescript 写评论demo
- 在docker中导入python的包时ImportError: libgthread-2.0.so.0: cannot open shared object file: No such file or directory
- python使用pysimplegui简单制作一个exe程序
- span&;不同字体
- 题解[LuoguP6222]「P6156简单题」加强版
- 如何将视频作为Windows桌面动态壁纸,两步就可以搞定!
- linux端口探测
- Python3.6多线程爬虫
- gulp安装出错
- .Net最小工作线程对应用程序性能的影响