解決 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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/63285.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/63285.shtml
英文地址,請注明出處:http://en.pswp.cn/web/63285.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringBoot 手動實現動態切換數據源 DynamicSource (中)

大家好&#xff0c;我是此林。 SpringBoot 手動實現動態切換數據源 DynamicSource &#xff08;上&#xff09;-CSDN博客 在上一篇博客中&#xff0c;我帶大家手動實現了一個簡易版的數據源切換實現&#xff0c;方便大家理解數據源切換的原理。今天我們來介紹一個開源的數據源…

ASCII碼簡介以及在php中的使用

什么是 ASCII&#xff1f; ASCII&#xff08;American Standard Code for Information Interchange&#xff0c;美國信息交換標準代碼&#xff09;是一種字符編碼標準&#xff0c;用于在計算機、通信設備及其他設備中表示文字、符號和控制信息。它最早于 1963 年由美國國家標準…

前端學習一

一 進程與線程 線程是進程執行的最小單位&#xff0c;進程是系統分配任務的最小單位。 一個進程可執行最少一個線程。線程分為子線程和主線程。 主線程關閉則子線程關閉。 二 瀏覽器進程 瀏覽器是多進程多線程應用。 進程包括&#xff1a; 瀏覽器進程 負責程序交互渲染…

Go vendor

博主在編寫Go代碼時&#xff0c;遇到了這樣一個問題&#xff1a;想要修改某個外部包&#xff0c;添加幾個函數&#xff0c;而其余功能繼續使用&#xff0c;經過調研&#xff0c;發現可以將Go的外部包源碼復制到項目本地&#xff0c;對包的代碼進行修改&#xff0c;從而達到目的…

EasyExcel 動態設置表格的背景顏色和排列

項目中使用EasyExcel把數據以excel格式導出&#xff0c;其中設置某一行、某一列單元格的背景顏色、排列方式十分常用&#xff0c;記錄下來方便以后查閱。 1. 導入maven依賴&#xff1a; <dependency><groupId>com.alibaba</groupId><artifactId>easy…

概率論得學習和整理23:EXCEL 數據透視表基礎操作

目錄 1 選擇數據&#xff0c;插入數據透視表 2 選擇數據透視表生成位置 3 出現了數據透視表的面板 4 數據透視表的基本結構認識 4.1 交叉表/列聯表 4.2 row, column, cell 一個新增的篩選器&#xff0c;就這么簡單 4.3 可以只添加 rowcell/值 &#xff0c;也可以colu…

計算機網絡從誕生之初到至今的發展歷程

前言 "上網"&#xff0c;相信大家對這個動詞已經不再陌生&#xff0c;網 通常指的是網絡&#xff1b;在 2024 年的今天&#xff0c;網絡已經滲透到了每個人的生活中&#xff0c;成為其不可或缺的一部分&#xff1b;你此時此刻在看到我的博客&#xff0c;就是通過網絡…

C# 讀取EXCEL的數據批量插入單個PDF里的多個位置

C# 讀取EXCEL的數據批量插入單個PDF里的多個位置 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Reflection; usin…

圖論筆記1

1.1鄰接矩陣儲存法 //創建:二維數組vector<vector<int>> graph(n,vector<int>(n,0));//儲存for(int i0;i<m;i){int x1,x2;cin>>x1>>x2;graph[x1-1][x2-1]1;}1.2鄰接表儲存法 補充&#xff1a;c中的list是鏈表 鏈接 //創建&#xff1a;數組…

GB28181系列三:GB28181流媒體服務器ZLMediaKit

我的音視頻/流媒體開源項目(github) GB28181系列目錄 目錄 一、ZLMediaKit介紹 二、 ZLMediaKit安裝、運行(Ubuntu) 1、安裝 2、運行 3、配置 三、ZLMediaKit使用 一、ZLMediaKit介紹 ZLMediaKit是一個基于C11的高性能運營級流媒體服務框架&#xff0c;項目地址&#xf…

iPhone恢復技巧:如何從 iPhone 恢復丟失的照片

在計算機時代&#xff0c;我們依靠手機來捕捉和存儲珍貴的回憶。但是&#xff0c;如果您不小心刪除或丟失了手機上的照片怎么辦&#xff1f;這真的很令人沮喪和煩惱&#xff0c;不是嗎&#xff1f;好吧&#xff0c;如果您在 iPhone 上丟失了照片&#xff0c;您不必擔心&#xf…

如何將你的 Ruby 應用程序從 OpenSearch 遷移到 Elasticsearch

作者&#xff1a;來自 Elastic Fernando Briano 將 Ruby 代碼庫從 OpenSearch 客戶端遷移到 Elasticsearch 客戶端的指南。 OpenSearch Ruby 客戶端是從 7.x 版 Elasticsearch Ruby 客戶端分叉而來的&#xff0c;因此代碼庫相對相似。這意味著當將 Ruby 代碼庫從 OpenSearch 遷…

LeetCode 283.移動零(超簡單講解)

283.移動零 題目示例示例1示例2 解題思路快慢指針實現設計 詳細代碼 題目 給定一個數組 nums&#xff0c;編寫一個函數將所有 0 移動到數組的末尾&#xff0c;同時保持非零元素的相對順序。 請注意 &#xff0c;必須在不復制數組的情況下原地對數組進行操作。 示例 示例1 …

Day8 神經網絡中的導數基礎

Day8 神經網絡中的導數基礎 導數的定義 導數&#xff08;Derivative&#xff09;是微積分中的一個核心概念&#xff0c;用于描述函數在某一點的變化率。簡單來說&#xff0c;導數就是函數值隨自變量微小變化而產生的變化量&#xff0c;即斜率或變化率。假設有一個函數 f ( x…

RequestContextHolder 與 HttpServletRequest 的聯系

1. 什么是 RequestContextHolder&#xff1f; RequestContextHolder 是 Spring 框架 提供的一個工具類&#xff0c;用于在當前線程中存儲和獲取與請求相關的上下文信息。它是基于 ThreadLocal 實現的&#xff0c;能夠保證每個線程獨立存儲和訪問請求信息。 與 HttpServletReq…

SpringBoot配置和啟動

1.內部配置加載順序&#xff1a; 加載規則 加載順序和優先級與配置文件所在路徑有關優先級高的配置會覆蓋優先級低的配置&#xff0c;配置文件會全部加載&#xff0c;遇到相同的配置高優先級覆蓋低優先級命令行參數 -spring.config.location 自定義配置文件路徑&#xff0c;可…

【視頻生成模型】——Hunyuan-video 論文及代碼講解和實操

&#x1f52e;混元文生視頻官網 | &#x1f31f;Github代碼倉庫 | &#x1f3ac; Demo 體驗 | &#x1f4dd;技術報告 | &#x1f60d;Hugging Face 文章目錄 論文詳解基礎介紹數據預處理 &#xff08;Data Pre-processing&#xff09;數據過濾 (Data Filtering)數據標注 (Data…

52 基于單片機的超聲波、溫濕度、光照檢測分階段報警

目錄 一、主要功能 二、硬件資源 三、程序編程 四、實現現象 一、主要功能 1.通過DHT11模塊讀取環境溫度和濕度: 2.將濕度、障礙物距顯示在lcd1602上面&#xff0c;第一行顯示溫度和濕度,格式為:xxCyy%&#xff0c;第二行顯示超聲波傳感器測得的距離&#xff0c;格式為:Di…

大數據與AI:從分析到預測的躍遷

引言&#xff1a;數據時代的新紀元 從每天的社交分享到企業的運營決策&#xff0c;數據早已成為現代社會不可或缺的資源。我們正置身于一個數據爆炸的時代&#xff0c;數以億計的信息流實時生成&#xff0c;為人類帶來了前所未有的洞察能力。然而&#xff0c;數據的價值并不僅限…

3D視覺[一]3D計算機視覺

3D視覺[一]3D計算機視覺 3D計算機視覺概述 像機標定 文章目錄 3D視覺[一]3D計算機視覺前言一、人類視覺二、計算機視覺2.1 計算機視覺的研究目的2.2 計算機視覺的研究任務2.3 計算機視覺的研究方法2.4 視覺計算理論2.5 馬爾框架中計算機視覺表達的四個層次2.5.1 圖像&#xff…