最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

mybatis中的if-test判斷解讀

 更新時(shí)間:2024年11月04日 08:59:17   作者:xinlianluohan  
在使用MyBatis進(jìn)行條件判斷時(shí),如果條件中涉及到字符與數(shù)字的比較,需要特別注意比較方式,例如,在<if>標(biāo)簽中,比較數(shù)字“1”時(shí),應(yīng)將其寫(xiě)在雙引號(hào)中,或者使用.toString()方法,避免直接使用字符'1'進(jìn)行比較

mybatis if-test判斷解讀

<if test="takeWay == '0'">】mybatis的if判斷

單個(gè)的字符要寫(xiě)到雙引號(hào)里面才行,改為<if test='takeWay == "1"'>或者改為<if test="takeWay == '1'.toString() ">

.xml文件的部分代碼

<insert id="insertDelivery" parameterType="com.zuci.request.DeliveryPreferenceReq">     
    insert cx_customer_deliverypreference     
    <trim prefix="(" suffix=")" suffixOverrides=",">           
        .... 此處省略       
        <if test="takeWay == '1' and workday != null ">         
            WORKDAY,       
        </if>       
        ....     
    </trim>
         
    <trim prefix="values (" suffix=")" suffixOverrides=",">          
        .... 此處省略          
        <if test="takeWay == '1' and workday != null ">            
            #{workday, jdbcType=VARCHAR},     
        </if>      
        ....   
    </trim>
</insert>

takeWay == “1”處出錯(cuò),導(dǎo)致不執(zhí)行if判斷中的sql,運(yùn)行程序不報(bào)錯(cuò),沒(méi)有任何提示。去掉takeWay == “1” and 則可執(zhí)行。對(duì)此我百思不得其解,

因?yàn)樽约河袑?xiě)過(guò)如下代碼,是沒(méi)錯(cuò)的。

<if test="messageType == 'senderReceiveSuccess' ">
      ......
</if>
  • 把<if test="takeWay == '1' and workday != null ">
  • 改為<if test='takeWay == "1" and workday != null '>
  • 或改為<if test="takeWay == '1'.toString() and workday != null ">即可。

原因是:mybatis是用OGNL表達(dá)式來(lái)解析的,在OGNL的表達(dá)式中,’1’會(huì)被解析成字符,java是強(qiáng)類(lèi)型的,char 和 一個(gè)string 會(huì)導(dǎo)致不等,所以if標(biāo)簽中的sql不會(huì)被解析。

總結(jié)下使用方法:?jiǎn)蝹€(gè)的字符要寫(xiě)到雙引號(hào)里面或者使用.toString()才行!

使用Mybatis時(shí),常常會(huì)判斷屬性是否為空

  • POJO
private Integer status;//狀態(tài),可能為0、1、2、3。
  • Mapper XML
<sql>
  <trim prefix="where" prefixOverrides="and | or ">
      //...省略其他
      <if test="status != null and status !=''">and status = #{status}</if> 
  <trim prefix="where" prefixOverrides="and | or ">
</sql>

當(dāng)status的值為 0時(shí)該where SQL and status = 0并未正常拼接,也就是說(shuō)test內(nèi)的表達(dá)式為false,從而導(dǎo)致查詢結(jié)果錯(cuò)誤。但是,顯然該值(Integer :0)!= null也!= ' ',應(yīng)該為true才對(duì)。

當(dāng)status為Integer類(lèi)型,并且status值為0時(shí),該if判斷卻為false。

當(dāng)status為0時(shí),Mybatis會(huì)解析成'' 空字符串。

為了避免這個(gè)問(wèn)題,改成下面這樣寫(xiě),去掉對(duì)空字符的判斷,就解決了該問(wèn)題

<if test="status != null">and status = #{status}</if> 

原因分析

通過(guò)Debug MyBatis源碼順藤摸瓜找到了IfSqlNode類(lèi),該類(lèi)用來(lái)處理動(dòng)態(tài)SQL的<if>節(jié)點(diǎn),方法public boolean apply(DynamicContext context)用來(lái)構(gòu)造節(jié)點(diǎn)內(nèi)的SQL語(yǔ)句。

if (evaluator.evaluateBoolean(test, context.getBindings())

該代碼便是解析

<if test="status !=null and status !=''">

test內(nèi)表達(dá)式的關(guān)鍵,如果表達(dá)式為true則拼接SQL,否則忽略。

public class IfSqlNode implements SqlNode {
  private ExpressionEvaluator evaluator;
  private String test;
  private SqlNode contents;

  public IfSqlNode(SqlNode contents, String test) {
    this.test = test;
    this.contents = contents;
    this.evaluator = new ExpressionEvaluator();
  }

  public boolean apply(DynamicContext context) {
    if (evaluator.evaluateBoolean(test, context.getBindings())) {
      contents.apply(context);
      return true;
    }
    return false;
  }
}

打開(kāi)ExpressionEvaluator 類(lèi),發(fā)現(xiàn)解析表達(dá)式使用的是OGNL,如果你使用過(guò)古老的Struts框架你應(yīng)該對(duì)它不陌生。

通過(guò)

OgnlCache.getValue(expression, parameterObject);

可以看到表達(dá)式的值是從緩存中獲取的,由此可知MyBatis竟然對(duì)表達(dá)式也做了緩存,以提高性能。

public class ExpressionEvaluator {  
  public boolean evaluateBoolean(String expression, Object parameterObject) {  
    Object value = OgnlCache.getValue(expression, parameterObject);  
    if (value instanceof Boolean) return (Boolean) value;  
    if (value instanceof Number) return !new BigDecimal(String.valueOf(value)).equals(BigDecimal.ZERO);  
    return value != null;  
  }  

跟進(jìn)去看看,終于找到了解析表達(dá)式的方法

private static Object parseExpression(String expression)

該方法會(huì)先從緩存取值,如果沒(méi)有便進(jìn)行解析并放入緩存中,然后調(diào)用

Ognl.getValue(parseExpression(expression), root)

獲得表達(dá)式的值。

public class OgnlCache {

  private static final Map<String, ognl.Node> expressionCache = new ConcurrentHashMap<String, ognl.Node>();

  public static Object getValue(String expression, Object root) throws OgnlException {
    return Ognl.getValue(parseExpression(expression), root);
  }

  private static Object parseExpression(String expression) throws OgnlException {
    try {
      Node node = expressionCache.get(expression);
      if (node == null) {
        node = new OgnlParser(new StringReader(expression)).topLevelExpression();
        expressionCache.put(expression, node);
      }
      return node;
    } catch (ParseException e) {
      throw new ExpressionSyntaxException(expression, e);
    } catch (TokenMgrError e) {
      throw new ExpressionSyntaxException(expression, e);
    }
  }

至于

Ognl.getValue(parseExpression(expression), root)

是如何運(yùn)作的,如果你有興趣可以自行跟下去一探究竟,本文就不贅述了。

到此為止,我們已經(jīng)知道MyBatis的表達(dá)式是用OGNL處理的了,這一點(diǎn)已經(jīng)夠了。

下面我們?nèi)GNL官網(wǎng)看看是不是我們的表達(dá)式語(yǔ)法有問(wèn)題從而導(dǎo)致該問(wèn)題的發(fā)生。

Interpreting Objects as Booleans

Any object can be used where a boolean is required. OGNL interprets objects as booleans like this:

  • If the object is a Boolean, its value is extracted and returned;
  • If the object is a Number, its double-precision floating-point value is compared with zero; non-zero is treated as true, zero as false;
  • If the object is a Character, its boolean value is true if and only if its char value is non-zero;
  • Otherwise, its boolean value is true if and only if it is non-null.

果然,如果對(duì)象是一個(gè)Number類(lèi)型,值為0時(shí)將被解析為false,否則為true,浮點(diǎn)型0.00也是如此。

OGNL對(duì)于boolean的定義和JavaScript有點(diǎn)像,即'' == 0 == false。

這也就不難理解

<if test="status != null and status !=''">and status = #{status}</if>

當(dāng)status=0時(shí)出現(xiàn)的問(wèn)題了,顯然0!=''是不成立的,導(dǎo)致表達(dá)式的值為false。

將表達(dá)式修改為

<if test="status != null">and status = #{status}</if>

該問(wèn)題便迎刃而解。

問(wèn)題的根源還是來(lái)自編碼的不規(guī)范,只有String類(lèi)型才需要判斷是否!='',其他類(lèi)型完全沒(méi)有這個(gè)必要,可能是開(kāi)發(fā)人員為了省事直接復(fù)制上一行拿過(guò)來(lái)改一改或是所使用的MyBatis生成工具不嚴(yán)謹(jǐn)導(dǎo)致該問(wèn)題的發(fā)生。

這里有必要再提一個(gè)“坑”,如果你有類(lèi)似于String str ="A"; <if test="str!= null and str == 'A'">這樣的寫(xiě)法時(shí),你要小心了。

因?yàn)閱我?hào)內(nèi)如果為單個(gè)字符時(shí),OGNL將會(huì)識(shí)別為Java 中的 char類(lèi)型,顯然String 類(lèi)型與char類(lèi)型做==運(yùn)算會(huì)返回false,從而導(dǎo)致表達(dá)式不成立。

解決方法很簡(jiǎn)單,修改為<if test='str!= null and str == "A"'>即可。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot和前端Vue的跨域問(wèn)題及解決方案

    SpringBoot和前端Vue的跨域問(wèn)題及解決方案

    所謂跨域就是從 A 向 B 發(fā)請(qǐng)求,如若他們的地址協(xié)議、域名、端口都不相同,直接訪問(wèn)就會(huì)造成跨域問(wèn)題,跨域是非常常見(jiàn)的現(xiàn)象,這篇文章主要介紹了解決SpringBoot和前端Vue的跨域問(wèn)題,需要的朋友可以參考下
    2023-11-11
  • Java中創(chuàng)建ZIP文件的方法

    Java中創(chuàng)建ZIP文件的方法

    本文通過(guò)一段簡(jiǎn)單代碼給大家介紹了java中創(chuàng)建zip文件的方法,代碼超簡(jiǎn)單,感興趣的朋友跟隨腳本之家小編一起看看吧
    2018-06-06
  • SpringBoot加載不出來(lái)application.yml文件的解決方法

    SpringBoot加載不出來(lái)application.yml文件的解決方法

    這篇文章主要介紹了SpringBoot加載不出來(lái)application.yml文件的解決方法,文中通過(guò)示例代碼講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作有一定的幫助,需要的朋友跟著小編來(lái)一起來(lái)學(xué)習(xí)吧
    2023-12-12
  • Java多線程并發(fā)開(kāi)發(fā)之DelayQueue使用示例

    Java多線程并發(fā)開(kāi)發(fā)之DelayQueue使用示例

    這篇文章主要為大家詳細(xì)介紹了Java多線程并發(fā)開(kāi)發(fā)之DelayQueue使用示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • Spring實(shí)戰(zhàn)之Bean的后處理器操作示例

    Spring實(shí)戰(zhàn)之Bean的后處理器操作示例

    這篇文章主要介紹了Spring實(shí)戰(zhàn)之Bean的后處理器操作,結(jié)合實(shí)例形式詳細(xì)分析了Bean的后處理器相關(guān)配置、操作方法及使用注意事項(xiàng),需要的朋友可以參考下
    2019-12-12
  • Java 二分查找算法的實(shí)現(xiàn)

    Java 二分查找算法的實(shí)現(xiàn)

    這篇文章主要介紹了Java 如何實(shí)現(xiàn)二分查找算法,幫助大家更好的理解和學(xué)習(xí)Java 算法,感興趣的朋友可以了解下
    2020-09-09
  • Java 多線程的同步代碼塊詳解

    Java 多線程的同步代碼塊詳解

    這篇文章主要介紹了Java 多線程的同步代碼塊,使用synchronized關(guān)鍵字創(chuàng)建線程同步方法是實(shí)現(xiàn)線程同步的關(guān)鍵,需要的朋友可以參考下
    2021-10-10
  • Java二叉樹(shù)路徑和代碼示例

    Java二叉樹(shù)路徑和代碼示例

    這篇文章主要介紹了Java二叉樹(shù)路徑和代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • java類(lèi)和對(duì)象原理與用法分析

    java類(lèi)和對(duì)象原理與用法分析

    這篇文章主要介紹了java類(lèi)和對(duì)象原理與用法,結(jié)合實(shí)例形式分析了java類(lèi)和對(duì)象的相關(guān)概念、功能、原理、使用技巧與操作注意事項(xiàng),需要的朋友可以參考下
    2020-02-02
  • 大模型chat/completions和completions區(qū)別解析

    大模型chat/completions和completions區(qū)別解析

    OpenAI的completions和chat/completions是兩個(gè)不同的端點(diǎn),completions用于單次文本補(bǔ)全,而chat/completions用于多輪對(duì)話生成,選擇哪個(gè)端點(diǎn)取決于你的具體需求,本文介紹大模型chat/completions和completions區(qū)別,感興趣的朋友一起看看吧
    2025-03-03

最新評(píng)論

温泉县| 青海省| 远安县| 卢氏县| 南宁市| 伊吾县| 峨眉山市| 竹山县| 台南市| 通州市| 北安市| 华蓥市| 瑞丽市| 阿克陶县| 图们市| 和顺县| 闻喜县| 安福县| 高安市| 嘉善县| 博白县| 永安市| 米脂县| 农安县| 重庆市| 科尔| 辽阳县| 冷水江市| 墨江| 定远县| 晋城| 乌拉特前旗| 汉阴县| 龙江县| 富锦市| 西藏| 湘西| 中西区| 房产| 土默特右旗| 沅江市|