解决 MyBatis 中空字符串与数字比较引发的条件判断错误

news2025/4/5 16:29:11

问题复现

假设你在 MyBatis 的 XML 配置中使用了如下代码:

<if test="isCollect != null">
    <choose>
        <when test="isCollect == 1">
            AND exists(select 1 from file_table imgfile2 where task.IMAGE_SEQ=imgfile2.IMAGE_SEQ and imgfile2.DOWNLOAD_STATUS = 1)
        </when>
        <when test="isCollect == 0">
            AND not exists(select 1 from file_table imgfile2 where task.IMAGE_SEQ=imgfile2.IMAGE_SEQ and imgfile2.DOWNLOAD_STATUS = 1)
        </when>
    </choose>
</if>

在这段代码中,通过 <choose> 标签对 isCollect 的值进行判断。如果 isCollect 的值为 1,则执行一个 exists 查询;如果 isCollect 的值为 0,则执行一个 not exists 查询。然而,实际运行时,当 isCollect空字符串 ("") 时,代码却会意外地执行到 test="isCollect == 0" 这一条件。
具体分析后,得出如果传入的 isCollect 是空字符串 "",由于 OGNL 类型转换的原因,空字符串会被转换为 0,导致条件判断意外地返回 true,从而执行 SQL 分支。本文将详细解析这个问题的根本原因,并提供有效的解决方案。

1. MyBatis 条件判断的执行流程

在 MyBatis 中,<if test="..."> 标签的条件表达式通过 OGNL(Object-Graph Navigation Language)引擎来解析。OGNL 可以动态地访问对象的属性,并执行表达式。MyBatis 将 test 属性中的表达式传递给 OGNL 引擎进行解析和计算,判断条件是否成立。

关键流程:
  • test 表达式解析test="isCollect == 0" 中的 isCollect == 0 会被 OGNL 解析并执行。
  • OGNL 类型转换:OGNL 在比较值时,会根据目标类型自动进行类型转换。例如,空字符串 "" 会被转换为 0(数字),导致条件 test="isCollect == 0" 被错误地评估为 true

2. 源码分析

要理解为什么空字符串 "" 被错误地转换为 0,我们需要查看 MyBatis 3.5.10 中的关键源码,特别是 OGNL 引擎如何处理这种类型转换。

a. IfSqlNode

IfSqlNode 负责解析 <if test="..."> 标签中的条件表达式。它会将 test 中的表达式交给 OGNL 引擎进行解析,然后根据条件结果决定是否生成 SQL 片段。

  • 源码路径org.apache.ibatis.scripting.xmltags.IfSqlNode
  • 主要方法apply(DynamicContext context)
# org.apache.ibatis.scripting.xmltags.IfSqlNode#apply
  @Override
  public boolean apply(DynamicContext context) {
    if (evaluator.evaluateBoolean(test, context.getBindings())) {
        // 如果为true,追加SQL片段
      contents.apply(context);
      return true;
    }
    return false;
  }
# org.apache.ibatis.scripting.xmltags.OgnlCache#getValue

  public static Object getValue(String expression, Object root) {
    try {
      Map context = Ognl.createDefaultContext(root, MEMBER_ACCESS, CLASS_RESOLVER, null);
      // 获取OGNL表达式的值
      return Ognl.getValue(parseExpression(expression), context, root);
    } catch (OgnlException e) {
      throw new BuilderException("Error evaluating expression '" + expression + "'. Cause: " + e, e);
    }
  }

  private static Object parseExpression(String expression) throws OgnlException {
    Object node = expressionCache.get(expression);
    if (node == null) {
      node = Ognl.parseExpression(expression);
      expressionCache.put(expression, node);
    }
    return node;
  }

在这个方法中,Ognl.getValue 会评估 test 条件的结果。如果 test 返回 true,那么相应的 SQL 片段就会被拼接到最终的查询中。
在这里插入图片描述
在这里插入图片描述

b. OGNL 类型转换:OgnlRuntime.convertValue

OGNL 在执行表达式时会对输入的值进行类型转换,尤其是在数字与字符串比较时。如果传入的是一个空字符串,OGNL 会将其隐式地转换为数字 0,导致条件判断被误判为 true

  • 源码路径ognl.OgnlRuntime
  • 关键方法convertValue(Object value, Class targetType)
public static Object convertValue(Object value, Class targetType) {
    if (targetType == int.class || targetType == Integer.class) {
        if (value instanceof String) {
            return Integer.valueOf((String) value);  // 将空字符串转换为 0
        }
    }
    return value;
}

在这段代码中,如果 value 是一个字符串,OGNL 会尝试将其转换为 Integer。空字符串会被转换为 0,导致条件 isCollect == 0 被误评估为 true

3. 解决方案

为了避免空字符串被错误地转换为 0,在 test 条件中显式检查 isCollect 是否为 null 或空字符串。

a. 显式检查 null 和空字符串

通过添加显式的判断条件,可以确保 isCollect 既不为 null 也不为空字符串,从而避免 test="isCollect == 0" 误判。改写后的 SQL 语句如下:

<if test="isCollect != null and isCollect != ''">
    <choose>
        <when test="isCollect == 1">
            AND exists(select 1 from file_table imgfile2 where task.IMAGE_SEQ=imgfile2.IMAGE_SEQ and imgfile2.DOWNLOAD_STATUS = 1)
        </when>
        <when test="isCollect == 0">
            AND not exists(select 1 from file_table imgfile2 where task.IMAGE_SEQ=imgfile2.IMAGE_SEQ and imgfile2.DOWNLOAD_STATUS = 1)
        </when>
    </choose>
</if>

通过这种方式,我们可以确保只有在 isCollect 不为 null 且不为空字符串时,才会进行 test="isCollect == 0" 判断,避免空字符串误判为 0

4. 总结

  • OGNL 表达式:在 MyBatis 中,test="isCollect == 0" 会使用 OGNL 解析,空字符串会被隐式转换为 0,导致条件判断错误。
  • 类型转换:OGNL 会自动将空字符串 "" 转换为数字 0,从而导致 test="isCollect == 0" 被误判为 true
  • 解决方案:通过显式检查 isCollect != null && isCollect != '' 来避免空字符串被误判为 0

参考资料

  • MyBatis 官方文档:MyBatis

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2260167.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何windows命令行使用kali?ssh连接高效又快捷

一、打开虚拟机kali进入cmd中 输入vim /etc/ssh/sshd_config&#xff0c;&#xff08;注意这里需要使用root权限&#xff09; 二、进入编辑文件页面 找到PermitRootLogin prohibit-password和 PasswordAuthentication no两行 将“prohibit-password”修改为“yes”&#xff0…

自动化测试之单元测试框架

单元测试框架 一、单元测试的定义 1&#xff1a;什么是单元测试&#xff1f; 还记不记得我们软件测试学习的时候&#xff0c;按照定义&#xff1a;单元测试就是对单个模块或者是单个函数进行测试&#xff0c;一般是开发做的&#xff0c;按照阶段来分&#xff0c;一般就是单元…

ansible部署nginx:1个简单的playbook脚本

文章目录 hosts--ventoryroles执行命令 使用ansible向3台centos7服务器上安装nginx hosts–ventory [rootstand playhook1]# cat /root/HOSTS # /root/HOSTS [webservers] 192.168.196.111 ansible_ssh_passpassword 192.168.196.112 ansible_ssh_passpassword 192.168.196.1…

SpringBoot左脚进门之Maven管理家

一、概念 Maven 是一个项目管理和整合工具。通过对 目录结构和构建生命周期 的标准化&#xff0c; 使开发团队用极少的时间就能够自动完成工程的基础构建配置。 Maven 简化了工程的构建过程&#xff0c;并对其标准化&#xff0c;提高了重用性。 Maven 本地仓库 (Local Reposi…

最短路----Dijkstra算法详解

简介 迪杰斯特拉&#xff08;Dijkstra&#xff09;算法是一种用于在加权图中找到单个源点到所有其他顶点的最短路径的算法。它是由荷兰计算机科学家艾兹格迪科斯彻&#xff08;Edsger Dijkstra&#xff09;在1956年提出的。Dijkstra算法适用于处理带有非负权重的图。迪杰斯特拉…

论文概览 |《Urban Analytics and City Science》2022.11 Vol.49 Issue.9

本次给大家整理的是《Environment and Planning B: Urban Analytics and City Science》杂志2022年11月第49卷第9期的论文的题目和摘要&#xff0c;一共包括19篇SCI论文&#xff01; 论文1 On economic and urban growth 经济发展与城市增长 【摘要】 The dominant imperativ…

软件安装不成功,一直出现“chrome_elf.dll丢失”问题是什么原因?“chrome_elf.dll丢失”要怎么解决和预防?

软件安装遇阻&#xff1a;“chrome_elf.dll丢失”问题全解析与解决方案 在软件安装与运行的过程中&#xff0c;我们时常会遇到各式各样的错误提示&#xff0c;其中“chrome_elf.dll丢失”便是较为常见的一种。这个错误不仅阻碍了软件的正常安装&#xff0c;也给用户带来了不小…

04面向对象篇(D4_OOT(D1_OOT - 面向对象测试))

目录 一、 面向对象影响测试 1. 封装性影响测试 2. 继承性影响测试 3. 多态性影响测试 二、 面向对象测试模型 三、 面向对象分析测试 1. 对象测试 2. 结构测试 3. 主题测试 4. 属性和实例关联测试 5. 服务和消息关联测试 四、面向对象设计测试 1. 对认定类测试 …

java之静态变量和方法(类变量、类方法)

1 类变量 1.1 简要介绍 由一个简单的程序引出&#xff1a; public class Example1 {int n;static int num 10; //有 static 修饰//此时 num 即为一个类变量&#xff08;静态变量&#xff09;&#xff0c;static 表示静态的//这个变量的最大特点是&#xff0c;它会被 Exampl…

朗致面试---IOS/安卓/Java/架构师

朗致面试---IOS/安卓/Java/架构师 一、面试概况二、总结三、算法题目参考答案 一、面试概况 一共三轮面试&#xff1a; 第一轮是逻辑行测&#xff0c;25道题目&#xff0c;类似于公务员考试题目&#xff0c;要求90分钟内完成。第二轮是技术面试&#xff0c;主要是做一些数据结…

五、网络层:控制平面,《计算机网络(自顶向下方法 第7版,James F.Kurose,Keith W.Ross)》

目录 一、导论 二、路由选择算法 2.1 路由&#xff08;route&#xff09;的概念 2.2 网络的图抽象 2.2.1 边和路由的代价 2.2.2 最优化原则 2.3 路由的原则 2.4 路由选择算法的分类 2.5 link state 算法 2.5.1 LS路由工作过程 2.5.2 链路状态路由选择&#xff08;lin…

音视频入门基础:MPEG2-TS专题(16)——PMT简介

一、引言 PMT&#xff08;Program Map Table&#xff09;与PAT表成对出现&#xff0c;其PID由PAT表给出。通过PMT表可以得到该节目包含的视频和音频信息&#xff0c;从而找到音视频流&#xff1a; 二、PMT表中的属性 根据《T-REC-H.222.0-202106-S!!PDF-E.pdf》第79页&#x…

结构变量的占用多少个字节

1、在linux中&#xff0c;这种写法比较清晰 struct gpio_led_data { u8 can_sleep; //如果定义了结构变量&#xff0c;则该成员占用1个字节 u8 blinking; //如果定义了结构变量&#xff0c;则该成员占用1个字节 }; struct gpio_leds_priv { int num_leds; //如…

网页端web内容批注插件:

感觉平时每天基本上90%左右的时间都在浏览器端度过&#xff0c;按理说很多资料都应该在web端输入并且输出&#xff0c;但是却有很多时间浪费到了各种桌面app中&#xff0c;比如说什么notion、语雀以及各种笔记软件中&#xff0c;以及导入到ipad的gn中&#xff0c;这些其实都是浪…

递归问题(c++)

递归设计思路 数列递归 : 如果一个数列的项与项之间存在关联性&#xff0c;那么可以使用递归实现 ; 原理 : 如果一个函数可以求A(n)&#xff0c;那么该函数就可以求A(n-1)&#xff0c;就形成了递归调用 ; 注意: 一般起始项是不需要求解的&#xff0c;是已知条件 这就是一个典型…

分布式 窗口算法 总结

前言 相关系列 《分布式 & 目录》《分布式 & 窗口算法 & 总结》《分布式 & 窗口算法 & 问题》 参考文献 《【算法】令牌桶算法》 固定窗口算法 简介 固定窗口算法是最简单的流量控制算法。固定窗口算法的核心原理是将系统的生命周期划分为一个个…

Linux shell的七大功能 --- history

1.直接输入“history” 这个命令可以显示出曾经使用过的命令&#xff08;最近时间的500条&#xff09; history 2.“history”命令也可以搭配其他命令一起使用。 例&#xff1a;history | grep "vim"&#xff0c;找出所有包含“vim”的记录&#xff1b; 也可以搭配…

C# 探险之旅:第九节 - 循环(for):无限循环的魔法轮盘!

嘿&#xff0c;勇敢的探险家们&#xff0c;欢迎回到C#的神秘世界&#xff01;在这一节里&#xff0c;我们将踏上一场关于循环的奇妙冒险&#xff0c;特别是那个能带我们无限次探险的“for循环”&#xff01;准备好了吗&#xff1f;让我们一起揭开for循环的神秘面纱&#xff0c;…

基于回溯法解决八皇后问题+以位运算方法优化n皇后问题(算法与数据结构期末设计)

文章目录 基于回溯法解决八皇后问题以位运算方法优化n皇后问题1. 八皇后问题问题描述2.回溯法求八皇后&#xff08;n皇后&#xff09;问题①由四皇后问题引入②皇后的占位问题③皇后的放置过程④放置过程中的问题⑤回溯算法核心⑥回溯算法的求解过程⑦验证算法和代码实现LeetCo…

python学opencv|读取图像(九)用numpy创建黑白相间灰度图

【1】引言 前述学习过程中&#xff0c;掌握了用numpy创建矩阵数据&#xff0c;把所有像素点的BGR取值设置为0&#xff0c;然后创建纯黑灰度图的方法&#xff0c;具体链接为&#xff1a; python学opencv|读取图像&#xff08;八&#xff09;用numpy创建纯黑灰度图-CSDN博客 在…