1. 程式人生 > >mybatis if標籤test 判斷數字遇到的問題

mybatis if標籤test 判斷數字遇到的問題

1、常見錯誤:

There is no getter for property named 'parentId' in 'class java.lang.Long'(或者String)

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'parentId' in 'class java.lang.Long'

sql是這樣寫的:

sql1:

複製程式碼
<
select id="queryByParentId" parameterType="long" resultMap="beanMap"> SELECT * FROM <include refid="t_pt_category"/> <where> isdel = 0 <if test="parentId != null"> AND parent_id = #{parentId} </if> </
where> ORDER BY parent_id </select>
複製程式碼

此時,就報了上面的錯誤。

解決1:

把<if>標籤去掉傳參還是直接傳遞傳遞long,如下:sql2

複製程式碼
<select id="queryByParentId" parameterType="long" resultMap="beanMap">
        SELECT * FROM <include refid="t_pt_category"/>
        <where>
            isdel = 0
           AND parent_id = #{parentId}
            
<!--<if test="parentId != null"> AND parent_id = #{parentId} </if> --> </where> ORDER BY parent_id </select>
複製程式碼

這樣也sql2是可以的。

解決2:保持sql1不變,在dao層把引數換成map型別,

Map<String, Object> params = new HashMap<>(1);
params.put("parentId", parentId);

此時再執行,是可以的。

(一般通用的全部的引數都是放到map中,這種最常用)

解決3:改寫sql1,如下,全部的引數都換成"_parameter",如下sql3:

複製程式碼
<select id="queryByParentId" parameterType="long" resultMap="beanMap">
        SELECT * FROM <include refid="t_pt_category"/>
        <where>
            isdel = 0
            <if test="_parameter != null">
                AND parent_id = #{_parameter}
            </if>
        </where>
        ORDER BY parent_id
    </select>
複製程式碼

此時直接傳遞long也是可以的。

第三部分:

最近在專案使用mybatis中碰到個問題 

Xml程式碼  收藏程式碼
  1. <if test="type=='y'">  
  2.     and status = 0   
  3. </if>  


當傳入的type的值為y的時候,if判斷內的sql也不會執行,抱著這個疑問就去看了mybatis是怎麼解析sql的。下面我們一起來看一下mybatis 的執行過程。 

DefaultSqlSession.class  121行 
Java程式碼  收藏程式碼
  1. public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {  
  2.     try {  
  3.       MappedStatement ms = configuration.getMappedStatement(statement);  
  4.       executor.query(ms, wrapCollection(parameter), rowBounds, handler);  
  5.     } catch (Exception e) {  
  6.       throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);  
  7.     } finally {  
  8.       ErrorContext.instance().reset();  
  9.     }  
  10.   }  




在 executor.query(ms, wrapCollection(parameter), rowBounds, handler); 
執行到BaseExecutor.class執行器中的query方法 
Java程式碼  收藏程式碼
  1. public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {  
  2.     BoundSql boundSql = ms.getBoundSql(parameter);  
  3.     CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);  
  4.     return query(ms, parameter, rowBounds, resultHandler, key, boundSql);  
  5.  }  

在query的方法中看到boundSql,是通過 ms.getBoundSql(parameter);獲取的。 

再點進去可以看到MappedStatement.class類中的getBoundSql方法 
Java程式碼  收藏程式碼
  1. public BoundSql getBoundSql(Object parameterObject) {  
  2.     BoundSql boundSql = sqlSource.getBoundSql(parameterObject);  
  3.     List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();  
  4.     if (parameterMappings == null || parameterMappings.size() <= 0) {  
  5.       boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);  
  6.     }  
  7.     // check for nested result maps in parameter mappings (issue #30)  
  8.     for (ParameterMapping pm : boundSql.getParameterMappings()) {  
  9.       String rmId = pm.getResultMapId();  
  10.       if (rmId != null) {  
  11.         ResultMap rm = configuration.getResultMap(rmId);  
  12.         if (rm != null) {  
  13.           hasNestedResultMaps |= rm.hasNestedResultMaps();  
  14.         }  
  15.       }  
  16.     }  
  17.     return boundSql;  
  18.   }  


看到其中有sqlSource.getBoundSql(parameterObject); sqlsource是一個介面。 
Java程式碼  收藏程式碼
  1. /** 
  2.  *  
  3.  * This bean represets the content of a mapped statement read from an XML file 
  4.  * or an annotation. It creates the SQL that will be passed to the database out 
  5.  * of the input parameter received from the user. 
  6.  *  
  7.  */  
  8. public interface SqlSource {  
  9.   BoundSql getBoundSql(Object parameterObject);  
  10. }  

類中getBoundSql是一個核心方法,mybatis 也是通過這個方法來為我們構建sql。BoundSql 物件其中儲存了經過引數解析,以及判斷解析完成sql語句。比如<if> <choose> <when> 都回在這一層完成,具體的完成方法往下看,那最常用sqlSource的實現類是DynamicSqlSource.class 


Java程式碼  收藏程式碼
  1. public class DynamicSqlSource implements SqlSource {  
  2.   private Configuration configuration;  
  3.   private SqlNode rootSqlNode;  
  4.   public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {  
  5.     this.configuration = configuration;  
  6.     this.rootSqlNode = rootSqlNode;  
  7.   }  
  8.   public BoundSql getBoundSql(Object parameterObject) {  
  9.     DynamicContext context = new DynamicContext(configuration, parameterObject);  
  10.     rootSqlNode.apply(context);  
  11.     SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);  
  12.     Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();  
  13.     SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());  
  14.     BoundSql boundSql = sqlSource.getBoundSql(parameterObject);  
  15.     for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {  
  16.       boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());  
  17.     }  
  18.     return boundSql;  
  19.   }  
  20. }  

核心方法是呼叫了rootSqlNode.apply(context); rootSqlNode是一個介面 
Java程式碼  收藏程式碼
  1. public interface SqlNode {  
  2.   boolean apply(DynamicContext context);  
  3. }  

可以看到類中 rootSqlNode.apply(context); 的方法執行就是一個遞迴的呼叫,通過不同的 
實現類執行不同的標籤,每一次appll是完成了我們<></>一次標籤中的sql建立,計算出標籤中的那一段sql,mybatis通過不停的遞迴呼叫,來為我們完成了整個sql的拼接。那我們主要來看IF的實現類IfSqlNode.class 
Java程式碼  收藏程式碼
  1. public class IfSqlNode implements SqlNode {  
  2.   private ExpressionEvaluator evaluator;  
  3.   private String test;  
  4.   private SqlNode contents;  
  5.   public IfSqlNode(SqlNode contents, String test) {  
  6.     this.test = test;  
  7.     this.contents = contents;  
  8.     this.evaluator = new ExpressionEvaluator();  
  9.   }  
  10.   public boolean apply(DynamicContext context) {  
  11.     if (evaluator.evaluateBoolean(test, context.getBindings())) {  
  12.       contents.apply(context);  
  13.       return true;  
  14.     }  
  15.     return false;  
  16.   }  
  17. }  


可以看到IF的實現中,執行了 if (evaluator.evaluateBoolean(test, context.getBindings()))  如果返回是false的話直接返回,否則繼續遞迴解析IF標籤以下的標籤,並且返回true。那繼續來看 evaluator.evaluateBoolean 的方法 

Java程式碼  收藏程式碼
  1. public class ExpressionEvaluator {  
  2.   public boolean evaluateBoolean(String expression, Object parameterObject) {  
  3.     Object value = OgnlCache.getValue(expression, parameterObject);  
  4.     if (value instanceof Boolean) return (Boolean) value;  
  5.     if (value instanceof Number) return !new BigDecimal(String.valueOf(value)).equals(BigDecimal.ZERO);  
  6.     return value != null;  
  7.   }  


關鍵點就在於這裡,在OgnlCache.getValue中呼叫了Ognl.getValue,看到這裡恍然大悟,mybatis是使用的OGNL表示式來進行解析的,在OGNL的表示式中,'y'會被解析成字元,因為java是強型別的,char 和 一個string 會導致不等。所以if標籤中的sql不會被解析。具體的請參照 OGNL 表示式的語法。到這裡,上面的問題終於解決了,只需要把程式碼修改成: 
Xml程式碼  收藏程式碼
  1. <if test='type=="y"'>  
  2.     and status = 0   
  3. </if>  

就可以執行了,這樣"y"解析出來是一個字串,兩者相等!

相關推薦

mybatis if標籤test 判斷數字遇到的問題

1、常見錯誤: There is no getter for property named 'parentId' in 'class java.lang.Long'(或者String) org.mybatis.spring.MyBatisSystemException: nested exception i

Mybatis if標籤判斷數字大小

1、if標籤語法 <select...> SQL語句1 <if test="條件表示式"> SQL語句2 </if> </select> 注意:條件表示式中大於號小於號用 gt,lt <if test=

mybatis if 標籤 判斷單個字元的不生效,其實這是個坑

需求: <if test="carrier != null and carrier !='' and carrier !='0'"> AND CARRIER = #{carrier} </if>要在carrier欄位不為null,'',和"0

JSTL c:If 標籤 test多條件下 判斷失效

正確寫法 <c:if test="${fn:containsIgnoreCase(showMenuFlag,'6') && isFlag == '1'}"> </c

mybatis if 標簽 判斷單個字符的不生效

解決辦法 sql ognl表達式 and tin tps arr 不為 單個字符 需求: <if test="carrier != null and carrier !=‘‘ and carrier !=‘0‘"> AND CARRIER = #{car

mybatis if 標籤使用總結

在專案開發中,mybatis <if> 標籤使用廣泛,本文講解if標籤的兩種使用方式 其一、使用 <if> 標籤判斷某一欄位是否為空 其二、使用 <if> 標籤判斷傳入引數是否相等 具體程式碼如下 資料庫表結構和資料 實體

下拉框使用c:if標籤進行判斷然後使用selected屬性實現選擇狀態

是否付款:<select name="isPay">             <option value="">請選擇</option>             <c:if test="${bill1.isPay == '已付款'}

c:if標籤判斷

判斷是否為空 <c:if test="${not empty feeType}">  注意:大括號外面不能為空。 ${orderNo.ethdOriginalOrderNo} </c:if> <c:if test="${empty str}">  str為空</c:

MyBatis if 標籤的坑,居然被我踩到了。。。

事件的原因是這樣的,需求是按條件查資料然後給前端展示就行了,寫的時候想著挺簡單的,不就是使用 MyBatis 動態 SQL 去查詢資料嗎? ![](https://img-blog.csdnimg.cn/img_convert/b2dc78f451c7a2e563bc877c7caa7ecb.webp?x

mybatis if test非空判斷數字0為什麼是false

1、去掉空字串判斷          <if test="version != null">xxxxx</if> 2、新增0值判斷     &nb

Mybatis if test 動態判斷數字時需要注意的問題

一 錯誤案例 mapper 程式碼 <if test="filter == 1">//filter型別為Integer and r.provider_code != #{pro

Mybatisif標籤中的整型判斷問題

用mybatis進行資料修改的時候,age屬性沒有賦值,但是我使用update的時候age這個屬性也被修改了。age屬性是一個int型別。 <set>           &

mybatis 對映檔案中,if標籤判斷字串相等

mybatis 對映檔案中,if標籤判斷字串相等,兩種方式: 因為mybatis對映檔案,是使用的ognl表示式,所以在判斷字串sex變數是否是字串Y的時候, <if test="sex=='Y'.toString()"> <if test = 'sex== "Y"'&g

struts標籤怎麼判斷request裡的屬性是否為空 <s:if test="${list==null}"> </s:if>

<s:if test="${weigou}==999">    //錯誤的 ${list==null} ,$實在strtus的配置檔案中取值用的,不是在jsp頁面裡取值的的吧,所以上面錯誤; 下面是對的 <s:if test="#request.weigou==999}"

MYBATISif test判斷中的注意事項

mybatis中有這樣一個SQL判斷, <if test="status != null and status !='' "> and a.STATUS = #{status,jdbcType=SMALLINT} </if> status是一個Byte型

mybatisif標籤判斷字串相等問題

mybatis 對映檔案中,if標籤判斷字串sfyx變數是否是字串Y的時候,發現並不管用:   <if test="sfyx=='Y' "> and 1=1 </if>   當時就尋思著可能是字元和字串的問題,改成雙引號試

Mybatisif標籤判斷字串

在做開發的時候遇到這樣一個問題:當傳入的type的值為y的時候,if判斷內的sql也不會執行。 <if test="type=='y'"> and status = 0 </if> 仔細想想:my

MyBatis if test 字串判斷問題

在使用 MyBatis if 進行條件判斷時,一直不正確,如下: <if test="status!= null and status=='OK'"> result = #{resul

mybatisif標籤判斷字串相等

今日按需求在mapper.xml中修改完一條sql的條件,感覺很輕鬆,如下所示:<if test="companyId != null and companyId !='' ">  <if test="companyFlag == '1'">  A

mybatis傳入引數為string型別時,if標籤判斷引數值的方法

我們在用mybatis框架時,當傳入的值為string型別時且需要判斷時,如果用和引數為map型別的值一樣的方法來寫<if test="引數名!=null and ''!=引數名“>這時查詢時會報錯:There is no getter for property