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

mybatis if test條件判斷語句中的判斷問題分析

 更新時間:2022年03月12日 08:55:18   作者:HansScopion  
這篇文章主要介紹了mybatis if test條件判斷語句中的判斷問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

if test條件判斷語句中的判斷問題

寫這個主要是描述在mybatis中要注意的問題,很不幸,自己沒注意,跳坑了。

我在mybatis中定義的sql語句如下

<if test="facilityOccupied != null and facilityOccupied != '' and facilityOccupied == 1 ">
?? ??? ??? ??? ?and z.serviceCount = 1
?? ??? ??? ?</if>?? ?
?? ??? ??? ?<if test="facilityOccupied != null and facilityOccupied != '' and facilityOccupied == 0 ">
?? ??? ??? ??? ?and z.serviceCount = 0
?? ??? ??? ?</if>

可以看到這里只是對傳入?yún)?shù)一個簡單的判斷。

controller層傳入一個Integer類型的facilityOccupied參數(shù)。

表面上看沒什么問題,當(dāng)傳入facilityOccupied = 1,測試結(jié)果很意外,它查詢了所有的結(jié)果,也就是說它沒有符合這個判斷facilityOccupied == 1 。

換一種寫法,在controller層中將傳入?yún)?shù)facilityOccupied改為String類型的,通過查詢結(jié)果可以看出它符合facilityOccupied == 1 這個判斷條件。

或使用equals()

<if test="facilityOccupied != null and facilityOccupied != '' and facilityOccupied.equals(1)">
?? ??? ??? ??? ?and z.serviceCount = 1
?? ??? ??? ?</if>?? ?
?? ??? ??? ?<if test="facilityOccupied != null and facilityOccupied != '' and facilityOccupied.equals(0)">
?? ??? ??? ??? ?and z.serviceCount = 0
?? ??? ??? ?</if>

所以,總結(jié)起來怎么說,在這個地方比較的并不是數(shù)值大小,而是物理地址,這個雙引號里面的1不是int類型也不是integer類型,而是String字符串類型,啊多么痛的領(lǐng)悟。

補充一下,test中eq 和 == 效果一樣,比較的是地址,所以比較值最好使用equals()。

mybatis 中if test判斷大坑

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

單個的字符要寫到雙引號里面才行,改為<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”處出錯,導(dǎo)致不執(zhí)行if判斷中的sql,運行程序不報錯,沒有任何提示。去掉takeWay == “1” and 則可執(zhí)行。對此我百思不得其解,

因為自己有寫過如下代碼,是沒錯的。

<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á)式來解析的,在OGNL的表達(dá)式中,’1’會被解析成字符,java是強類型的,char 和 一個string 會導(dǎo)致不等,所以if標(biāo)簽中的sql不會被解析。

總結(jié)下使用方法:單個的字符要寫到雙引號里面或者使用.toString()才行!

使用Mybatis時,常常會判斷屬性是否為空

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時該where SQL and status = 0并未正常拼接,也就是說test內(nèi)的表達(dá)式為false,從而導(dǎo)致查詢結(jié)果錯誤。但是,顯然該值(Integer :0)!= null也!= ' ',應(yīng)該為true才對。
  • 當(dāng)status為Integer類型,并且status值為0時,該if判斷卻為false。
  • 當(dāng)status為0時,Mybatis會解析成'' 空字符串。

為了避免這個問題,改成下面這樣寫,去掉對空字符的判斷,就解決了該問題

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

原因分析

通過Debug MyBatis源碼順藤摸瓜找到了IfSqlNode類,該類用來處理動態(tài)SQL的<if>節(jié)點,方法public boolean apply(DynamicContext context)用來構(gòu)造節(jié)點內(nèi)的SQL語句。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;
? }
}

打開ExpressionEvaluator 類,發(fā)現(xiàn)解析表達(dá)式使用的是OGNL,如果你使用過古老的Struts框架你應(yīng)該對它不陌生。通過OgnlCache.getValue(expression, parameterObject);可以看到表達(dá)式的值是從緩存中獲取的,由此可知MyBatis竟然對表達(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),該方法會先從緩存取值,如果沒有便進(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)是如何運作的,如果你有興趣可以自行跟下去一探究竟,本文就不贅述了。到此為止,我們已經(jīng)知道MyBatis的表達(dá)式是用OGNL處理的了,這一點已經(jīng)夠了。下面我們?nèi)GNL官網(wǎng)看看是不是我們的表達(dá)式語法有問題從而導(dǎo)致該問題的發(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.

果然,如果對象是一個Number類型,值為0時將被解析為false,否則為true,浮點型0.00也是如此。OGNL對于boolean的定義和JavaScript有點像,即'' == 0 == false。這也就不難理解<if test="status != null and status !=''">and status = #{status}</if>當(dāng)status=0時出現(xiàn)的問題了,顯然0!=''是不成立的,導(dǎo)致表達(dá)式的值為false。

將表達(dá)式修改為<if test="status != null">and status = #{status}</if>該問題便迎刃而解。該問題的根源還是來自編碼的不規(guī)范,只有String類型才需要判斷是否!='',其他類型完全沒有這個必要,可能是開發(fā)人員為了省事直接復(fù)制上一行拿過來改一改或是所使用的MyBatis生成工具不嚴(yán)謹(jǐn)導(dǎo)致該問題的發(fā)生。

這里有必要再提一個“坑”,如果你有類似于String str ="A"; <if test="str!= null and str == 'A'">這樣的寫法時,你要小心了。因為單引號內(nèi)如果為單個字符時,OGNL將會識別為Java 中的 char類型,顯然String 類型與char類型做==運算會返回false,從而導(dǎo)致表達(dá)式不成立。解決方法很簡單,修改為<if test='str!= null and str == "A"'>即可。

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

相關(guān)文章

  • 詳解SpringBoot?Start組件開發(fā)之記錄接口日志信息

    詳解SpringBoot?Start組件開發(fā)之記錄接口日志信息

    這篇文章主要為大家介紹了SpringBoot-Start組件開發(fā)之記錄接口日志信息詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 詳解java數(shù)組進(jìn)行翻轉(zhuǎn)的方法有哪些

    詳解java數(shù)組進(jìn)行翻轉(zhuǎn)的方法有哪些

    這篇文章主要介紹了詳解java數(shù)組進(jìn)行翻轉(zhuǎn)的方法有哪些,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Java正則表達(dá)式之分組和替換方式

    Java正則表達(dá)式之分組和替換方式

    這篇文章主要介紹了Java正則表達(dá)式之分組和替換方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • finally 一定會執(zhí)行(實例代碼)

    finally 一定會執(zhí)行(實例代碼)

    下面小編就為大家?guī)硪黄猣inally 一定會執(zhí)行(實例代碼)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07
  • Java中的單例模式詳解(完整篇)

    Java中的單例模式詳解(完整篇)

    Java單例模式應(yīng)該是看起來以及用起來簡單的一種設(shè)計模式,但是就實現(xiàn)方式以及原理來說,也并不淺顯,下面這篇文章主要給大家介紹了關(guān)于Java中單例模式的相關(guān)資料,需要的朋友可以參考下
    2021-11-11
  • spring定時任務(wù)執(zhí)行兩次及tomcat部署緩慢問題的解決方法

    spring定時任務(wù)執(zhí)行兩次及tomcat部署緩慢問題的解決方法

    這篇文章主要給大家介紹了關(guān)于spring定時任務(wù)執(zhí)行兩次及tomcat部署緩慢問題的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • springboot集成mybatis實例代碼

    springboot集成mybatis實例代碼

    本篇文章主要介紹了springboot集成mybatis實例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • Spring?Boot?Admin?添加報警提醒和登錄驗證功能的具體實現(xiàn)

    Spring?Boot?Admin?添加報警提醒和登錄驗證功能的具體實現(xiàn)

    報警提醒功能是基于郵箱實現(xiàn)的,當(dāng)然也可以使用其他的提醒功能,如釘釘或飛書機器人提醒也是可以的,但郵箱報警功能的實現(xiàn)成本最低,所以本文我們就來看郵箱的報警提醒功能的具體實現(xiàn)
    2022-01-01
  • 重學(xué)SpringBoot3之日志Logging使用方式

    重學(xué)SpringBoot3之日志Logging使用方式

    在日常開發(fā)中會遇到不同的異常,日志方便我們?nèi)ヅ挪樘幚?這篇文章主要給大家介紹了關(guān)于重學(xué)SpringBoot3之日志Logging使用方式的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-06-06
  • java實現(xiàn)Z字形掃描程序

    java實現(xiàn)Z字形掃描程序

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)Z字形掃描程序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03

最新評論

通城县| 福州市| 保山市| 宿州市| 左权县| 大厂| 淮安市| 宁都县| 宁化县| 景洪市| 丁青县| 德昌县| 翼城县| 青海省| 佛山市| 腾冲县| 封丘县| 唐河县| 松江区| 磐石市| 枣庄市| 永福县| 电白县| 栾城县| 长顺县| 芜湖市| 廉江市| 句容市| 庆云县| 沂南县| 芦山县| 衡南县| 电白县| 七台河市| 肥城市| 桑植县| 南城县| 上饶县| 长春市| 波密县| 扶余县|