MyBatis【源码探究 01】mapper.xml文件内<if test>标签判断参数值不等于null和空(当参数值为0)时筛选条件失效原因分析

简介: MyBatis【源码探究 01】mapper.xml文件内<if test>标签判断参数值不等于null和空(当参数值为0)时筛选条件失效原因分析

这个问题有不少小伙伴遇到过,也给出了解决方案,但是没有探究原因,这次读一下源码,看看原因在哪里。

1. 条件失效情况复现

  • Mapper.xml内的动态SQL如下【伪代码】
<select id="getInfoList" parameterType="java.util.Map" resultType="java.util.Map">
        SELECT
        *
        ${schemaName}${tableName}
        <where>
      <if test="viewId != null and viewId != ''">
                AND viewid = #{viewId}
            </if>
        </where>
  </select>
  • 调用动态SQL的方法如下【伪代码主要是显示一下传递的参数值】
Map<String, Object> mapParam = new HashMap<>(4);
mapParam.put("schemaName", "public");
mapParam.put("tableName", "info_table");
mapParam.put("viewId", 0);
queryInterface.getInfoList(mapParam);

查看查询结果会发现对 viewId 没有进行筛选。

2. 解决方法

去掉判断条件 and viewId != '' 即可。

<select id="getInfoList" parameterType="java.util.Map" resultType="java.util.Map">
        SELECT
        *
        ${schemaName}${tableName}
        <where>
            <if test="viewId != null">
                AND viewid = #{viewId}
            </if>
        </where>
  </select>

3. 源码解析

到底是为什么呢?我们找到 Mybatis 的 IfSqlNode 对象:

下边是打断点进行的参数追踪:

evaluator.evaluateBoolean(test, context.getBindings()) 为 true 时当前节点才会被应用。

进入 evaluateBoolean(test, context.getBindings()) 方法。

进入 OgnlCache.getValue(expression, parameterObject) 方法。

关键方法出现了:Ognl.getValue(parseExpression(expression), context, root);

我们找到 Ognl.getValue(parseExpression(expression), context, root)方法。

中间省略了部分方法,省略的方法主要是查找参数名称和参数值,不重要故未贴出。还有判断节点类型的过程,例子中用的的都是不等于类型的节点。下边的方法真正开始对表达式两侧的数值进行比较了。前半段的 viewId != null 不再贴出,只截图有问题的后半段:

进入最核心的方法比较方法 compareWithConversion(Object v1, Object v2)

看一下转换的过程:

问题的核心代码:

public static double doubleValue(Object value) throws NumberFormatException {
        if (value == null) {
            return 0.0D;
        } else {
            Class c = value.getClass();
            if (c.getSuperclass() == Number.class) {
                return ((Number)value).doubleValue();
            } else if (c == Boolean.class) {
                return (Boolean)value ? 1.0D : 0.0D;
            } else if (c == Character.class) {
                return (double)(Character)value;
            } else {
                String s = stringValue(value, true);
                return s.length() == 0 ? 0.0D : Double.parseDouble(s);
            }
        }
    }

由于 "".length() = 0,传递的参数 viewId 值是 0️⃣ 时 viewId != '' 就变成 0.0 != 0.0 这个自然是 false 此时,筛选条件不起作用就不足为奇了。

为什么会出现这种情况?是框架问题吗? 感觉不是的,我们在编程的时候,对数值类型值的判断本身就不应该使用 =='' 或者 !=''这样的条件。

目录
相关文章
|
11天前
|
SQL XML Java
mybatis-源码深入分析(一)
mybatis-源码深入分析(一)
|
2月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
1月前
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
30 1
|
3月前
|
SQL Java 数据库连接
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
60 3
|
2月前
|
XML 监控 数据格式
ROS 2 - Python、XML 和 YAML 编写 Launch 文件
ROS 2 - Python、XML 和 YAML 编写 Launch 文件
194 0
|
2月前
|
SQL Java 数据库连接
MyBatis Mapper.XML 标签使用说明
MyBatis Mapper.XML 标签使用说明
27 0
|
3月前
|
XML Java 数据格式
支付系统----微信支付20---创建案例项目--集成Mybatis-plus的补充,target下只有接口的编译文件,xml文件了,添加日志的写法
支付系统----微信支付20---创建案例项目--集成Mybatis-plus的补充,target下只有接口的编译文件,xml文件了,添加日志的写法
|
5月前
|
SQL 关系型数据库 MySQL
实时计算 Flink版产品使用合集之从MySQL同步数据到Doris时,历史数据时间字段显示为null,而增量数据部分的时间类型字段正常显示的原因是什么
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStreamAPI、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
2月前
|
SQL 关系型数据库 MySQL
在 MySQL 中使用 IS NULL
【8月更文挑战第12天】
591 0
在 MySQL 中使用 IS NULL
|
5月前
|
SQL 关系型数据库 MySQL
python在mysql中插入或者更新null空值
这段代码是Python操作MySQL数据库的示例。它执行SQL查询从表`a_kuakao_school`中选取`id`,`university_id`和`grade`,当`university_id`大于0时按升序排列。然后遍历结果,根据`row[4]`的值决定`grade`是否为`NULL`。若不为空,`grade`被格式化为字符串;否则,设为`NULL`。接着构造UPDATE语句更新`university`表中对应`id`的`grade`值,并提交事务。重要的是,字符串`NULL`不应加引号,否则更新会失败。
130 2