日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【mybatis】IF判断的坑 (实现if test= status == 'zhangsan')

發布時間:2025/4/16 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【mybatis】IF判断的坑 (实现if test= status == 'zhangsan') 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自:http://blog.csdn.net/z69183787/article/details/51589171

最近在項目使用mybatis中碰到個問題?

Xml代碼??
  • <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判断的坑 (实现if test= status == 'zhangsan')的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。