基于mybatis中test條件中單引號雙引號的問題
test條件中單引號雙引號問題
在mybatis中test判斷條件中使用單引號會報錯 通常使用雙引號
通常test后的判斷條件寫在雙引號內(nèi),但是當條件中判斷使用字符串時應(yīng)該如下方式開發(fā)
<when ?test=“channel ==null” > <when ?test='channel =="QT"' >
具體原因
為單引號會被mybatis默認為字符類型,若為單字符可以使用單引號。否則會報錯。
動態(tài)sql中test的一些問題
mybatis動態(tài)sql中OGNL中type=="1"和type='1'的區(qū)別
最近在mybatis中使用OGNL所遇到的坑: 一點雞肋: type=="1"和type='1'的區(qū)別
//CountryDao.java public interface CountryDao { ? ? CountryDo getByType(@Param("type") String type); } //CountryManager.java @Component("countryManager") public class CountryManager { ? ? @Autowired ? ? private CountryDao countryDao; ? ? public CountryDo getByType(String type){ ? ? ? ? return countryDao.getByType(type); ? ? } }
mapper.xml:
//.xml <select id="getByType" resultType="com.github.**.domain.CountryDo"> ? ? <choose> ? ? ? //注意寫法`type=='0'` ? ? ? ? <when test="type == '0'"> ? ? ? ? ? ? SELECT * FROM country WHERE country_id = 2 ? ? ? ? </when> ? ? ? ? <otherwise> ? ? ? ? ? ? SELECT * FROM country WHERE country_id = 3; ? ? ? ? </otherwise> ? ? </choose> </select>
測試案例:
@Test public void getByTypeTest() throws JsonProcessingException { ? ? String type = "0"; ? ? CountryDo countryDo = countryManager.getByType(type); ? ? ObjectMapper mapper = new ObjectMapper(); ? ? String json = mapper.writeValueAsString(countryDo); ? ? System.out.println(json); }
理想情況下,當type=0時返回的是country_id=2的結(jié)果
測試結(jié)果:
{"countryId":3,"country":"American Samoa","lastUpdate":"2006-02-15 04:44:00.0"}
居然返回的是country_id=3的結(jié)果
百度了才知道
原來傳值進去的是String類型,而mybatis的動態(tài)sql中的OGNL表達式不會將單引號包裹的char類型的內(nèi)容轉(zhuǎn)成String類型,并且String類型和char類型直接比較一定是不相等的。所以輸出是country_id=3的結(jié)果
解決方案
將<when test="type == '0'">換成<when test='type == "0"'>即可,即將單引號換成雙引號
0==’'問題
一個更有趣的問題,如果將mapper.xml文件內(nèi)容換成:
<select id="getByType" resultType="com.github.sijing.domain.CountryDo"> ? ? <choose> ? ? ? ? <when test="0 ==''"> ? ? ? ? ? ? SELECT * FROM country WHERE country_id = 2 ? ? ? ? </when> ? ? ? ? <otherwise> ? ? ? ? ? ? SELECT * FROM country WHERE country_id = 3; ? ? ? ? </otherwise> ? ? </choose> </select>
測試案例不變:
@Test public void getByTypeTest() throws JsonProcessingException { ? ? //此時傳值已經(jīng)沒有影響了 ? ? String type = "0"; ? ? CountryDo countryDo = countryManager.getByType(type); ? ? ObjectMapper mapper = new ObjectMapper(); ? ? String json = mapper.writeValueAsString(countryDo); ? ? System.out.println(json); }
測試結(jié)果為:
{"countryId":2,"country":"Algeria","lastUpdate":"2006-02-15 04:44:00.0"}
怎么還是country_id=2的結(jié)果?,難道0==''??
查看mybatis源碼發(fā)現(xiàn),比如對于動態(tài)sql<if>標簽的解析:
// IfSqlNode. @Override ?public boolean apply(DynamicContext context) { ? ?if (evaluator.evaluateBoolean(test, context.getBindings())) { ? ? ?contents.apply(context); ? ? ?return true; ? ?} ? ?return false; ?}
在evaluator.evaluateBoolean方法中:
//ExpressionEvaluator.java OGNL表達式處理 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)).compareTo(BigDecimal.ZERO) != 0; ? } ? return value != null; }
當傳入值為0時,因為0是Number類型,所以被轉(zhuǎn)成了BigDecimal類型,并與0作比較,test的結(jié)果為true,所以返回的是country_id=2的結(jié)果,這個說法有誤。。。
再次調(diào)試,首先char ''被轉(zhuǎn)成了字符String"",大概在OgnlOps.java文件的isEqual方法中的(compareWithConversion(object1, object2) == 0),點進去發(fā)現(xiàn):
case NONNUMERIC: ? ? if ((t1 == NONNUMERIC) && (t2 == NONNUMERIC)) { ? ? ? ? if ((v1 instanceof Comparable) && v1.getClass().isAssignableFrom(v2.getClass())) { ? ? ? ? ? ? result = ((Comparable) v1).compareTo(v2); ? ? ? ? ? ? break; ? ? ? ? } else { ? ? ? ? ? ? throw new IllegalArgumentException("invalid comparison: " + v1.getClass().getName() + " and " ? ? ? ? ? ? ? ? ? ? + v2.getClass().getName()); ? ? ? ? } ? ? } ? ? // else fall through case FLOAT: case DOUBLE: ?? ?//v1=0, v2="" ? ? double dv1 = doubleValue(v1), ? ? dv2 = doubleValue(v2); ? ? return (dv1 == dv2) ? 0 : ((dv1 < dv2) ? -1 : 1);
在doubleValue方法中:
public static double doubleValue(Object value) ? ? ? ? throws NumberFormatException ? ? { ? ? ? ? if (value == null) return 0.0; ? ? ? ? Class c = value.getClass(); ? ? ? ? if (c.getSuperclass() == Number.class) return ((Number) value).doubleValue(); ? ? ? ? if (c == Boolean.class) return ((Boolean) value).booleanValue() ? 1 : 0; ? ? ? ? if (c == Character.class) return ((Character) value).charValue(); ? ? ? ? String s = stringValue(value, true); ? ? ? ? return (s.length() == 0) ? 0.0 : Double.parseDouble(s); ? ? }
坑坑坑!!!
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot 自定義404、500錯誤提示頁面的實現(xiàn)
springboot 默認已經(jīng)提供了一套處理異常的機制。在 springboot 中提供了一個名為 BasicErrorController 的類來處理 /error 請求,然后跳轉(zhuǎn)到默認顯示異常的頁面來展示異常信息,本文就詳細的介紹一下,感興趣的可以了解一下2021-11-11Java?properties?和?yml?的區(qū)別解析
properties和yml都是Spring?Boot支持的兩種配置文件,它們可以看做Spring?Boot在不同時期的兩種“產(chǎn)品”,這篇文章主要介紹了Java?properties?和?yml?的區(qū)別,需要的朋友可以參考下2023-02-02java如何將一個float型數(shù)的整數(shù)部分和小數(shù)分別輸出顯示
這篇文章主要介紹了java如何將一個float型數(shù)的整數(shù)部分和小數(shù)分別輸出顯示,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07spring使用RedisTemplate操作Redis數(shù)據(jù)庫
這篇文章主要介紹了spring使用RedisTemplate操作Redis數(shù)據(jù)庫,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03Mybatis使用useGeneratedKeys獲取自增主鍵的方法
這篇文章主要給大家介紹了關(guān)于Mybatis使用useGeneratedKeys獲取自增主鍵的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用Mybatis具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09spring如何快速穩(wěn)定解決循環(huán)依賴問題
這篇文章主要介紹了spring如何快速穩(wěn)定解決循環(huán)依賴問題,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03Java concurrency之AtomicReference原子類_動力節(jié)點Java學(xué)院整理
AtomicReference是作用是對"對象"進行原子操作。這篇文章主要介紹了Java concurrency之AtomicReference原子類,需要的朋友可以參考下2017-06-06