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 此时,筛选条件不起作用就不足为奇了。

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

目录
相关文章
|
6月前
|
XML Java 数据库连接
mybatis中在xml文件中通用查询结果列如何使用
mybatis中在xml文件中通用查询结果列如何使用
403 0
|
12天前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
5月前
|
SQL Java 数据库连接
MYBATIS获取参数值
MYBATIS获取参数值
MYBATIS获取参数值
|
13天前
|
SQL 缓存 Java
MyBatis如何关闭一级缓存(分注解和xml两种方式)
MyBatis如何关闭一级缓存(分注解和xml两种方式)
41 5
|
5月前
|
XML Java 数据库连接
MyBatis入门——MyBatis XML配置文件(3)
MyBatis入门——MyBatis XML配置文件(3)
71 6
|
2月前
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
44 1
|
4月前
|
Java 数据库连接 数据库
mybatis plus 更新值为null的字段
mybatis plus 更新值为null的字段
57 7
|
3月前
|
SQL Java 数据库连接
MyBatis Mapper.XML 标签使用说明
MyBatis Mapper.XML 标签使用说明
38 0
|
5月前
|
SQL XML Java
后端数据库开发JDBC编程Mybatis之用基于XML文件的方式映射SQL语句实操
后端数据库开发JDBC编程Mybatis之用基于XML文件的方式映射SQL语句实操
71 3
|
4月前
|
XML Java 数据格式
支付系统----微信支付20---创建案例项目--集成Mybatis-plus的补充,target下只有接口的编译文件,xml文件了,添加日志的写法
支付系统----微信支付20---创建案例项目--集成Mybatis-plus的补充,target下只有接口的编译文件,xml文件了,添加日志的写法