解决 MyBatis 中空字符串与数字比较引发的条件判断错误
问题复现
假设你在 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@Overridepublic 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#getValuepublic 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
相关文章:
解决 MyBatis 中空字符串与数字比较引发的条件判断错误
问题复现 假设你在 MyBatis 的 XML 配置中使用了如下代码: <if test"isCollect ! null"><choose><when test"isCollect 1">AND exists(select 1 from file_table imgfile2 where task.IMAGE_SEQimgfile2.IMAGE_SEQ and im…...
python 词向量的代码解读 self.word_embeds = nn.Embedding(vocab_size, embedding_dim) 解释下
在PyTorch中,nn.Embedding 是一个用于将稀疏的离散数据表示为密集的嵌入向量的模块。这在自然语言处理(NLP)任务中非常常见,例如在处理单词或字符时,我们通常需要将这些离散的标识符转换为可以被神经网络处理的连续值向…...
记一次:使用C#创建一个串口工具
前言:公司的上位机打不开串口,发送的时候设备总是关机,因为和这个同事关系比较好,编写这款软件是用C#编写的,于是乎帮着解决了一下(是真解决了),然后整理了一下自己的笔记 一、开发…...
Android Studio新版本的一个资源id无法找到的bug解决
Android Studio新版本的一个资源id无法找到的bug解决 文章目录 Android Studio新版本的一个资源id无法找到的bug解决一、前言二、Android Studio的无法获取到资源id的bug1、一段简单的Java代码1、错误现象2、错误解决方法 三、其他1、小结2、gradle.properties文件 其他相关属性…...
Datawhale AI冬令营(第一期)--零基础定制你的专属大模型
本文主要简述如何快速完成和一些小细节 第一步下载嬛嬛数据集 数据来源:self-llm/dataset/huanhuan.json at master datawhalechina/self-llm GitHub 注意:1.一定是数据集下载完成一定是.json结尾的 2.这个是github的网址,可能会遇到打不开的情况 …...
LLMs之APE:基于Claude的Prompt Improver的简介、使用方法、案例应用之详细攻略
LLMs之APE:基于Claude的Prompt Improver的简介、使用方法、案例应用之详细攻略 目录 Prompt Improver的简介 0、背景痛点 1、优势 2、实现思路 Prompt优化 示例管理 提示词评估 Prompt Improver的使用方法 1、使用方法 Prompt Improver的案例应用 1、Kap…...
【Unity人形布娃娃插件】Ragdoll Animator
Ragdoll Animator 是一款为 Unity 引擎开发的插件,专注于让角色在运行时动态地切换到布娃娃物理系统(Ragdoll Physics)。该插件帮助开发者轻松创建逼真的角色动画过渡效果,尤其适用于需要角色碰撞、摔倒、受击或其他物理反应的场景…...
跨团队协作中目标一致性至关重要
在团队协作的复杂拼图里,目标一致性是那根贯穿始终的主线,缺之则拼图难成,团队亦难达预期之效。 且看这样一个实例:部门承接了业务方一项紧急的数据处理需求,此任务犹如一座亟待攀登的险峰,落在了 A 团队…...
Excel的文件导入遇到大文件时
Excel的文件导入向导如何把已导入数据排除 入起始行,选择从哪一行开始导入。 比如,前两行已经导入了,第二次导入的时候排除前两行,从第三行开始,就将导入起始行设置为3即可,且不勾选含标题行。 但遇到大文…...
使用字典进行动态编程
在你的程序中,你想要执行各种计算,例如计算卫星的总数。 此外,当你进行更高级的编程时,你可能会发现你需要从文件或数据库中加载此类信息,而不是直接编码到 Python 中。 为了帮助支持这些场景,Python 使你…...
机器学习02-发展历史补充
机器学习02-发展历史补充 文章目录 机器学习02-发展历史补充1-机器学习个人理解1-初始阶段:统计学习和模式识别(20世纪50年代至80年代)2-第二阶段【集成时代】【核方法】(20世纪90年代至2000年代初期)3-第三阶段【特征…...
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之计数器与累加器(一)
学习背景: 在现实生活中一些需要计数的场景下我们会用到计数器,如空姐手里记录乘客的计数器,跳绳手柄上的计数器等。累加器是累加器求和,以得到最后的结果。计数器和累加器它们虽然是基础知识,但是应用广泛࿰…...
Android的SurfaceView和TextureView介绍
文章目录 前言一、什么是SurfaceView ?1.1 SurfaceView 使用示例1.2 SurfaceView 源码概述1.3 SurfaceView 的构造与初始化1.4 SurfaceHolder.Callback 回调接口1.5 SurfaceView 渲染机制 二、什么是TextureView?2.1 TextureView 使用示例2.2 TextureVie…...
Scala的集合
1 集合简介 1)Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable 特质。 2)对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两 个包 不可变集合&am…...
1. Flink自定义Source
一. Source 简介 DataStream是Flink的低级API,用于进行数据的实时处理,Flink编程模型分为Source、Transformation、Sink三个部分,如下图所示。 默认Flink提供了大量的内置Source,常见的Source如下: 基于文件的Sour…...
关于LinuxWindows双系统在八月更新后出现的问题
问题描述类似于:Verifying shim SBAT data failed: If you are, this is caused by a reported problem in the August update if you can get into Windows, either uninstall the August update, or open Command Prompt as administrator and run this command,…...
VMware:如何在CentOS7上开启22端口
打开虚拟机:【编辑】【虚拟机网络设置】 其中填入的虚拟机IP地址是虚拟机中centos的IP地址,虚拟机端口为需要映射的centos端口 配置好之后保存,打开宿主机 win cmd telnet 192.168.1.26 22 如果出现上述窗口,则说明已经成功开放…...
ubuntu远程桌面开启opengl渲染权限
背景 最近用windows的【远程桌面连接】登录ubuntu后(xrdp协议),发现gl环境是集显的,但是本地登录ubuntu桌面后是独显(英伟达),想要在远程桌面上也用独显渲染环境。 一、查看是独显还是集显环境…...
从小学题到技术选型哲学:以智能客服系统为例,解读相关AI技术栈20241211
🧠💡从小学题到技术选型哲学:以智能客服系统为例,解读相关AI技术栈 引言:从小学数学题到技术智慧 📚✨ 在小学数学题中,有这样一道问题: “一个长方形变成平行四边形后,…...
【C语言练习(5)—回文数判断】
C语言练习(5) 文章目录 C语言练习(5)前言问题问题解析结果总结 前言 通过回文数练习,巩固数字取余和取商如何写代码 问题 输入一个五位数判断是否为回文数? 问题解析 回文数是指正读反读都一样的整数。…...
【Rust 学习笔记】Rust 基础数据类型介绍——数组、向量和切片
博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 博客内容主要围绕: 5G/6G协议讲解 高级C语言讲解 Rust语言讲解 文章目录 Rust 基础数据类型介绍——数组、向量和切片一、数组、向量和…...
2024年特别报告,「十大生活方式」研究数据报告
“一朵花成轻奢品、一只玩偶掀抢购狂潮、一片荒地变文旅圣地…” 近年爆火的野兽派、Jellycat、阿那亚等诸多品牌,与消费者选择的生活方式息息相关。 今年小红书的内容种草、直播电商,也都依循着“生活方式”的轨迹。生活方式的价值所向,可…...
R中单细胞RNA-seq分析教程 (5)
引言 本系列开启R中单细胞RNA-seq数据分析教程[1],持续更新,欢迎关注,转发! 10. 伪时间细胞排序 如前所述,在 UMAP 嵌入中看到的背侧端脑细胞形成的类似轨迹的结构,很可能代表了背侧端脑兴奋性神经元的分化…...
openpnp - Too many misdetects - retry and verify fiducial/nozzle tip detection
文章目录 openpnp - Too many misdetects - retry and verify fiducial/nozzle tip detection概述笔记环境光最好弱一些在设备标定时,吸嘴上不要装绿色屏蔽片如果吸嘴不在底部相机中间,先检查设置底部相机坐标调整底部相机坐标 吸嘴校验的细节底部相机坐…...
不与最大数相同的数字之和
不与最大数相同的数字之和 C语言代码C 语言代码Java语言代码Python语言代码 💐The Begin💐点点关注,收藏不迷路💐 输出一个整数数列中不与最大数相同的数字之和。 输入 输入分为两行: 第一行为N(N为接下来数的个数&…...
CSS学习记录11
CSS布局 - display属性 display属性是用于控制布局的最终要的CSS属性。display 属性规定是否/如何显示元素。每个HTML元素都有一个默认的display值,具体取决于它的元素类型。大多数元素的默认display值为block 或 inline。 块级元素(block element&…...
D95【python 接口自动化学习】- pytest进阶之fixture用法
day95 pytest的fixture详解(二) 学习日期:20241210 学习目标:pytest基础用法 -- pytest的fixture详解(二) 学习笔记: fixture(autouseTrue) func的autouse是TRUE时,所有函数方法…...
Abaqus断层扫描三维重建插件CT2Model 3D V1.1版本更新
更新说明 Abaqus AbyssFish CT2Model3D V1.1版本更新新增对TIF、TIFF图像文件格式的支持。本插件用户可免费获取升级服务。 插件介绍 插件说明: Abaqus基于CT断层扫描的三维重建插件CT2Model 3D 应用案例: ABAQUS基于CT断层扫描的细观混凝土三维重建…...
隐式对象和泛型
implicit object 作用: case class DatabaseConfig(driver:String,url:String)//作为函数的隐士参数的默认值implicit object MySqlDefault extends DatabaseConfig("mysql","localhost:443")def getConn(implicit config: DatabaseConfig):Uni…...
CSS的颜色表示方式
以下介绍几种常见的CSS颜色表示方式: 颜色名称 html和css规范中定义了147种可用的颜色名用的相对较少 16进制表示 css三原色:红、绿、蓝16进制的颜色值: #rrggbb16进制整数规定颜色成分,所有的值均介于 00 - ff 之间ÿ…...
宁波h5模板建站/关键字c语言
https://download.csdn.net/download/weixin_57836618/69499559 运行截图 1.启动界面 2.主页面、按时间正序排序、倒序排序 3.编辑页面 5.分享功能...
网站建设公司取名/网络信息发布平台
来自:http://www.think-in-g.net/ghawk/blog/2012/02/decoupling-view-controllers-with-key-value-observing/ 首 先,将数据容器剥离到控制器以外。其次,将各个控制器之间的依赖关系切断,在控制器初始化后,通过KVO机制…...
西宁网站制作哪家公司好/制作网页代码大全
. . . 代码展示如下: #include<stdio.h> int main() {int a,b,i,j,k,m;scanf("%d%d",&a,&b);if(a>b){//判断输入的数据谁大谁小ib;ka;} else{ia;kb;}mi;//最大公约数for(i;i>0;i--)//从最小的数开始往0递减if(a%i0 && b%i0)…...
专业网站建设设计/带佣金的旅游推广平台有哪些
2、计一记(记账) 优化界面,将操作改简洁美观,可以从其他支付软件中读取消费记录并写入软件中。 3、校园管家(关于每天的运动步数、包含日历选择日期) 注册好像并没有什么实际意义,可以弄一个好友…...
商城网站设计定制/百度竞价推广费用
个人整理精品文档,仅供个人学习使用个人整理精品文档,仅供个人学习使用个人整理精品文档,仅供个人学习使用PAGE / NUMPAGES个人整理精品文档,仅供个人学习使用《计算机组成原理》试卷一一.选择题(每小题分,…...
太原做网站baidu/免费外链代发
CSS里实现水平居中非常容易,inline元素用text-align:center;,block元素用margin:auto;就行了。但要实现垂直居中确是一大难题。本篇收集了一些已知的方案,整理出来,以备将来取用。代码可以从GitHub上下载。 Flex弹性盒子absolute绝…...