需求: 有四个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,不建议使用覆盖。建议定义新的参数名,避免有坑。

mybatis bind 标签 覆盖 复杂对象的某个属性值 问题。的更多相关文章

  1. 【mybatis】标签条件中判断入参属性值是否包含子字符串

    可以直接使用 contains判断 <foreach collection="list" item="item" index="index&qu ...

  2. 【java】【反射】反射实现判断发生了修改操作,判断两个对象是否发生属性值的变更,判断两个List集合内对象的属性值是否发生变更

    java的反射实现: 判断发生了修改操作,判断两个对象是否发生属性值的变更,判断两个List集合内对象的属性值是否发生变更 今日份代码: package com.sxd.streamTest; imp ...

  3. MyBatis bind标签的用法

    From<MyBatis从入门到精通> <!-- 4.5 bind用法 bind标签可以使用OGNL表达式创建一个变量并将其绑定到上下文中. 需求: concat函数连接字符串,在M ...

  4. mybatis bind标签

    开门见山的说,平时写模糊查询,一直用${name},例如: select * from table where name like '%${name}%' 后来知道了,这样写可能会引发sql注入,于是 ...

  5. mybatis bind 标签

    bind 标签可以使用 OGNL 表达式创建一个变量井将其绑定到上下文中.在前面的例子中, UserMapper.xml 有一个 selectByUser 方法,这个方法用到了 like 查询条件,部 ...

  6. java中两个对象间的属性值复制,比较,转为map方法实现

    package com.franson.study.util; import java.lang.reflect.InvocationTargetException; import java.lang ...

  7. JSON字符串反序列化成对象_部分属性值反序列化失败

    简介:本人在开发webapi接口时遇到了:一个复杂的Json字符串在反序列化为对象时报,无法发序列化其中的一个属性对象? 使用方法: InternalRecommendRequestFormModel ...

  8. Java反射获取对象VO的属性值(通过Getter方法)

    有时候,需要动态获取对象的属性值. 比如,给你一个List,要你遍历这个List的对象的属性,而这个List里的对象并不固定.比如,这次User,下次可能是Company. e.g. 这次我需要做一个 ...

  9. [转]js对象中取属性值(.)和[ ]的区别

    原文地址:https://www.jianshu.com/p/6a76530e4f8f 今天在写js的过程中遇到这么一个问题,取一个对象的属性值,通过obj.keys怎么都取不出来,但是用obj[ke ...

  10. java对象生成随意属性值

    public class RandomObjectValue { public static <T> T getObject(Class<?> clazz) { T t = n ...

随机推荐

  1. Deer_GF之框架介绍

    介绍一下Deer_GameFramework_Wolong,这个框架是我自己这几年经验及自己摸索出来缝合出来一套包含优秀库及开发工具可以直接上手快速开发游戏的框架.       缝合东西包括游戏框架G ...

  2. golang json字符串合并操作

    用于两个json格式的字符串合并,当B向A合并时,共有的字段,将用B字段的值(伴随类型一起覆盖),非共有的,A的字段保留,B的字段新增. example代码: package main import ...

  3. k8s ingress 报错整理

    问题: Error from server (InternalError): error when creating "ingress-rules-demo1.yaml": Int ...

  4. UE4笔记索引

    图形 渲染 延迟渲染 三维渲染流程 渲染优化 基本渲染 材质 材质节点组合 节点分类 特别的属性 其他 坐标空间与切线空间 坐标轴 编码 平台相关 UBT编译 命令行 程序到CPU路径 C++与蓝图互 ...

  5. 使用shell判断文件夹中是否包含文件

    #!/bin/bash directory="/path/to/directory" if [ $(ls -A $directory) ]; then echo "有文件 ...

  6. IDEA的常用快捷键和文档注释

    IDEA的常用快捷键 Alt + 回车 导入包,自动修正 Ctrl + N 查找类 Ctrl + Shift + N 查找文件 Ctrl + Alt + N 格式化代码 Ctrl + Alt + O ...

  7. 前端下载csv文件

    var str = [ 'ssssssssssssssssssssssssssssssssssssssss' ]; var uri = 'data:text/csv;charset=utf-8,%EF ...

  8. CI2454国产8位RISC核SoC芯片

    Ci2454是一款集成无线收发器和8位RISC(精简指令集)MCU的SOC芯片.主要应用在遥控玩具.智能灯控.数据透传.工业控制等领域.无线收发器主要特性 工作在 2.4GHz ISM 频段. 调制方 ...

  9. Java基础——Scanner扫描字符数组出现问题

    问题:今天写的一个简易学生信息类出现了如下问题Exception in thread "main" java.util.InputMismatchException: For in ...

  10. JAVA流程控制(查漏补缺)

    JAVA流程控制(查漏补缺) 目录 JAVA流程控制(查漏补缺) if 判断 switch多重选择 编译检查 for循环 for each break和continue if 判断 要判断引用类型的变 ...