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中碰到個問題
- <if test="type=='y'">
- and status = 0
- </if>
當傳入的type的值為y的時候,if判斷內的sql也不會執行,抱著這個疑問就去看了mybatis是怎麼解析sql的。下面我們一起來看一下mybatis 的執行過程。
DefaultSqlSession.class 121行
Java程式碼
- public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
- try {
- MappedStatement ms = configuration.getMappedStatement(statement);
- executor.query(ms, wrapCollection(parameter), rowBounds, handler);
- } catch (Exception e) {
- throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
- } finally {
- ErrorContext.instance().reset();
- }
- }
在 executor.query(ms, wrapCollection(parameter), rowBounds, handler);
執行到BaseExecutor.class執行器中的query方法
Java程式碼
- public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
- BoundSql boundSql = ms.getBoundSql(parameter);
- CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
- return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
- }
在query的方法中看到boundSql,是通過 ms.getBoundSql(parameter);獲取的。
再點進去可以看到MappedStatement.class類中的getBoundSql方法
Java程式碼
- public BoundSql getBoundSql(Object parameterObject) {
- BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
- List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
- if (parameterMappings == null || parameterMappings.size() <= 0) {
- boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
- }
- // check for nested result maps in parameter mappings (issue #30)
- for (ParameterMapping pm : boundSql.getParameterMappings()) {
- String rmId = pm.getResultMapId();
- if (rmId != null) {
- ResultMap rm = configuration.getResultMap(rmId);
- if (rm != null) {
- hasNestedResultMaps |= rm.hasNestedResultMaps();
- }
- }
- }
- return boundSql;
- }
看到其中有sqlSource.getBoundSql(parameterObject); sqlsource是一個介面。
Java程式碼
- /**
- *
- * This bean represets the content of a mapped statement read from an XML file
- * or an annotation. It creates the SQL that will be passed to the database out
- * of the input parameter received from the user.
- *
- */
- public interface SqlSource {
- BoundSql getBoundSql(Object parameterObject);
- }
類中getBoundSql是一個核心方法,mybatis 也是通過這個方法來為我們構建sql。BoundSql 物件其中儲存了經過引數解析,以及判斷解析完成sql語句。比如<if> <choose> <when> 都回在這一層完成,具體的完成方法往下看,那最常用sqlSource的實現類是DynamicSqlSource.class
Java程式碼
- public class DynamicSqlSource implements SqlSource {
- private Configuration configuration;
- private SqlNode rootSqlNode;
- public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
- this.configuration = configuration;
- this.rootSqlNode = rootSqlNode;
- }
- public BoundSql getBoundSql(Object parameterObject) {
- DynamicContext context = new DynamicContext(configuration, parameterObject);
- rootSqlNode.apply(context);
- SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
- Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
- SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
- BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
- for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
- boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
- }
- return boundSql;
- }
- }
核心方法是呼叫了rootSqlNode.apply(context); rootSqlNode是一個介面
Java程式碼
- public interface SqlNode {
- boolean apply(DynamicContext context);
- }
可以看到類中 rootSqlNode.apply(context); 的方法執行就是一個遞迴的呼叫,通過不同的
實現類執行不同的標籤,每一次appll是完成了我們<></>一次標籤中的sql建立,計算出標籤中的那一段sql,mybatis通過不停的遞迴呼叫,來為我們完成了整個sql的拼接。那我們主要來看IF的實現類IfSqlNode.class
Java程式碼
- 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;
- }
- }
可以看到IF的實現中,執行了 if (evaluator.evaluateBoolean(test, context.getBindings())) 如果返回是false的話直接返回,否則繼續遞迴解析IF標籤以下的標籤,並且返回true。那繼續來看 evaluator.evaluateBoolean 的方法
Java程式碼
- 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;
- }
關鍵點就在於這裡,在OgnlCache.getValue中呼叫了Ognl.getValue,看到這裡恍然大悟,mybatis是使用的OGNL表示式來進行解析的,在OGNL的表示式中,'y'會被解析成字元,因為java是強型別的,char 和 一個string 會導致不等。所以if標籤中的sql不會被解析。具體的請參照 OGNL 表示式的語法。到這裡,上面的問題終於解決了,只需要把程式碼修改成:
Xml程式碼
- <if test='type=="y"'>
- and status = 0
- </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
Mybatis中if標籤中的整型判斷問題
用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}"
MYBATIS中if test判斷中的注意事項
mybatis中有這樣一個SQL判斷, <if test="status != null and status !='' "> and a.STATUS = #{status,jdbcType=SMALLINT} </if> status是一個Byte型
mybatis中if標籤判斷字串相等問題
mybatis 對映檔案中,if標籤判斷字串sfyx變數是否是字串Y的時候,發現並不管用: <if test="sfyx=='Y' "> and 1=1 </if> 當時就尋思著可能是字元和字串的問題,改成雙引號試
Mybatis中 if標籤判斷字串
在做開發的時候遇到這樣一個問題:當傳入的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
mybatis中if標籤判斷字串相等
今日按需求在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