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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Mybatis3源码分析(05)-加载Configuration-加载MappedStatement

發布時間:2025/6/15 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mybatis3源码分析(05)-加载Configuration-加载MappedStatement 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

Mybatis3源碼分析(05)-加載Configuration-加載MappedStatement 博客分類: java mybatis

MappedStatement說明

一個MappedStatement對象對應Mapper配置文件中的一個select/update/insert/delete節點,主要描述的是一條SQL語句。其屬性有 [java] view plain copy
  • //節點中的id屬性加要命名空間??
  • private?String?id;??
  • //直接從節點屬性中取??
  • private?Integer?fetchSize;??
  • //直接從節點屬性中取??
  • private?Integer?timeout;??
  • private?StatementType?statementType;??
  • private?ResultSetType?resultSetType;??
  • //對應一條SQL語句??
  • private?SqlSource?sqlSource;??
  • ??
  • //每條語句都對就一個緩存,如果有的話。??
  • private?Cache?cache;??
  • //這個已經過時了??
  • private?ParameterMap?parameterMap;??
  • private?List<ResultMap>?resultMaps;??
  • private?boolean?flushCacheRequired;??
  • private?boolean?useCache;??
  • private?boolean?resultOrdered;??
  • //SQL的類型,select/update/insert/detete??
  • private?SqlCommandType?sqlCommandType;??
  • private?KeyGenerator?keyGenerator;??
  • private?String[]?keyProperties;??
  • private?String[]?keyColumns;??
  • ??
  • //是否有內映射??
  • private?boolean?hasNestedResultMaps;??
  • private?String?databaseId;??
  • private?Log?statementLog;??
  • private?LanguageDriver?lang;??
  • private?String[]?resultSets;??

  • 上面屬性都比較簡單,復雜的是SqlSource,下面有詳細的描述!

    XMLStatementBuilder.parseStatementNode()方法

    resultMap元素的解析已經分析完畢。與resultMap不一樣,XmlMapperBuilder在解析select/update /insert/delete的元素時會創建一個XMLStatementBuilder對象,解析的工作交由其方法 parseStatementNode()方法完成。 [java] view plain copy
  • private?void?buildStatementFromContext(List<XNode>?list,?String?requiredDatabaseId)?{??
  • ????for?(XNode?context?:?list)?{??
  • ??????//一個select/update/insert/delete元素創建一個XMLStatementBuilder對象??
  • ??????final?XMLStatementBuilder?statementParser?=?new?XMLStatementBuilder(configuration,?builderAssistant,?context,?requiredDatabaseId);??
  • ??????try?{??
  • ????????//將元素解析成MappedStatemenet對象,并加入到Configuration中去??
  • ????????statementParser.parseStatementNode();??
  • ??????}?catch?(IncompleteElementException?e)?{??
  • ????????configuration.addIncompleteStatement(statementParser);??
  • ??????}??
  • ????}??
  • 如下是parseStatementNode()方法的代碼 [java] view plain copy
  • public?void?parseStatementNode()?{??
  • ????String?id?=?context.getStringAttribute("id");??
  • ????String?databaseId?=?context.getStringAttribute("databaseId");??
  • ??
  • ????if?(!databaseIdMatchesCurrent(id,?databaseId,?this.requiredDatabaseId))?return;??
  • ??
  • ????Integer?fetchSize?=?context.getIntAttribute("fetchSize");??
  • ????Integer?timeout?=?context.getIntAttribute("timeout");??
  • ????String?parameterMap?=?context.getStringAttribute("parameterMap");??
  • ????String?parameterType?=?context.getStringAttribute("parameterType");??
  • ????Class<?>?parameterTypeClass?=?resolveClass(parameterType);??
  • ????String?resultMap?=?context.getStringAttribute("resultMap");??
  • ????String?resultType?=?context.getStringAttribute("resultType");??
  • ????String?lang?=?context.getStringAttribute("lang");??
  • ????LanguageDriver?langDriver?=?getLanguageDriver(lang);??
  • ??
  • ????Class<?>?resultTypeClass?=?resolveClass(resultType);??
  • ????String?resultSetType?=?context.getStringAttribute("resultSetType");??
  • ????//Statement的類型,對應jdbc里的三個類型:Statement、PreparedStatement、CallableStatement,默認使用PreparedStatement??
  • ????StatementType?statementType?=?StatementType.valueOf(context.getStringAttribute("statementType",?StatementType.PREPARED.toString()));??
  • ????//這個也是跟jdbc里相對應的,一般采用默認即可??
  • ????ResultSetType?resultSetTypeEnum?=?resolveResultSetType(resultSetType);??
  • ?????
  • ????//Sql的類型,select/update/insert/delete??
  • ????String?nodeName?=?context.getNode().getNodeName();??
  • ????SqlCommandType?sqlCommandType?=?SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));??
  • ????boolean?isSelect?=?sqlCommandType?==?SqlCommandType.SELECT;??
  • ????//是否刷新緩存??
  • ????boolean?flushCache?=?context.getBooleanAttribute("flushCache",?!isSelect);??
  • ????//是否使用緩存??
  • ????boolean?useCache?=?context.getBooleanAttribute("useCache",?isSelect);??
  • ????boolean?resultOrdered?=?context.getBooleanAttribute("resultOrdered",?false);??
  • ??
  • ????//不做分析??
  • ????//?Include?Fragments?before?parsing??
  • ????XMLIncludeTransformer?includeParser?=?new?XMLIncludeTransformer(configuration,?builderAssistant);??
  • ????includeParser.applyIncludes(context.getNode());??
  • ????//不做分析??
  • ????//?Parse?selectKey?after?includes?and?remove?them.??
  • ????processSelectKeyNodes(id,?parameterTypeClass,?langDriver);??
  • ??????
  • ????//生成SqlSource對象,這個對象非常重要,接下來詳細分析??
  • ????//?Parse?the?SQL?(pre:?<selectKey>?and?<include>?were?parsed?and?removed)??
  • ????SqlSource?sqlSource?=?langDriver.createSqlSource(configuration,?context,?parameterTypeClass);??
  • ????String?resultSets?=?context.getStringAttribute("resultSets");??
  • ????String?keyProperty?=?context.getStringAttribute("keyProperty");??
  • ????String?keyColumn?=?context.getStringAttribute("keyColumn");??
  • ??????
  • ????//自動生成key,這里也不做討論??
  • ????KeyGenerator?keyGenerator;??
  • ????String?keyStatementId?=?id?+?SelectKeyGenerator.SELECT_KEY_SUFFIX;??
  • ????keyStatementId?=?builderAssistant.applyCurrentNamespace(keyStatementId,?true);??
  • ????if?(configuration.hasKeyGenerator(keyStatementId))?{??
  • ??????keyGenerator?=?configuration.getKeyGenerator(keyStatementId);??
  • ????}?else?{??
  • ??????keyGenerator?=?context.getBooleanAttribute("useGeneratedKeys",??
  • ??????????configuration.isUseGeneratedKeys()?&&?SqlCommandType.INSERT.equals(sqlCommandType))??
  • ????????????new?Jdbc3KeyGenerator()?:?new?NoKeyGenerator();??
  • ????}??
  • ????//生成MappedStatement對象,并加到Configuration中??
  • ????builderAssistant.addMappedStatement(id,?sqlSource,?statementType,?sqlCommandType,??
  • ????????fetchSize,?timeout,?parameterMap,?parameterTypeClass,?resultMap,?resultTypeClass,??
  • ????????resultSetTypeEnum,?flushCache,?useCache,?resultOrdered,???
  • ????????keyGenerator,?keyProperty,?keyColumn,?databaseId,?langDriver,?resultSets);??
  • ??}??
  • 上在方法里附件解析一些基本的屬性外還有兩個主要的部分
  • SqlSource的構建過程
    [java] view plain copy
  • SqlSource?sqlSource?=?langDriver.createSqlSource(configuration,?context,?parameterTypeClass);??
  • MappedStatement的構建過程 [java] view plain copy
  • builderAssistant.addMappedStatement(id,?sqlSource,?statementType,?sqlCommandType,??
  • ???????fetchSize,?timeout,?parameterMap,?parameterTypeClass,?resultMap,?resultTypeClass,??
  • ???????resultSetTypeEnum,?flushCache,?useCache,?resultOrdered,???
  • ???????keyGenerator,?keyProperty,?keyColumn,?databaseId,?langDriver,?resultSets);??
  • SqlSource構建過程

    SqlSource接口

    [java] view plain copy
  • /**?
  • ?*?Represents?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.?
  • ?*?
  • ?*?@author?Clinton?Begin?
  • ?*/??
  • public?interface?SqlSource?{??
  • ??
  • ??BoundSql?getBoundSql(Object?parameterObject);??
  • ??
  • }??
  • SqlSource表示從mapper.xml或注解中讀取的sql內容,該sql一般還不能都被直接執行,例如 [html] view plain copy
  • <select?id="selectUserDetail"?resultMap="detailUserResultMap">??
  • ????<!--CDATA里內容會都解析成一個SqlSource對象-->??
  • ????????????????<![CDATA[?
  • ????????????select?user_id,user_name,user_type,cust_id?from?tf_f_user?a?where?a.user_id=#${userId}?
  • ????????]]>/select>??
  • SqlSource只有一個方法:getBoundSql(paramenterObject),其中paramenterObject為運行sql里的實際參數

    BoundSql

    [java] view plain copy
  • /**?
  • ?*?An?actual?SQL?String?got?form?an?{@link?SqlSource}?after?having?processed?any?dynamic?content.?
  • ?*?The?SQL?may?have?SQL?placeholders?"?"?and?an?list?(ordered)?of?an?parameter?mappings??
  • ?*?with?the?additional?information?for?each?parameter?(at?least?the?property?name?of?the?input?object?to?read??
  • ?*?the?value?from).??
  • ?*?</br>?
  • ?*?Can?also?have?additional?parameters?that?are?created?by?the?dynamic?language?(for?loops,?bind...).?
  • ?*/??
  • /**?
  • ?*?@author?Clinton?Begin?
  • ?*/??
  • public?class?BoundSql?{??
  • ??
  • ??private?String?sql;??
  • ??private?List<ParameterMapping>?parameterMappings;??
  • ??private?Object?parameterObject;??
  • ??private?Map<String,?Object>?additionalParameters;??
  • ??private?MetaObject?metaParameters;??
  • ??
  • ??public?BoundSql(Configuration?configuration,?String?sql,?List<ParameterMapping>?parameterMappings,?Object?parameterObject)?{??
  • ????this.sql?=?sql;??
  • ????this.parameterMappings?=?parameterMappings;??
  • ????this.parameterObject?=?parameterObject;??
  • ????this.additionalParameters?=?new?HashMap<String,?Object>();??
  • ????this.metaParameters?=?configuration.newMetaObject(additionalParameters);??
  • ??}??
  • ??
  • ??public?String?getSql()?{??
  • ????return?sql;??
  • ??}??
  • ??
  • ??public?List<ParameterMapping>?getParameterMappings()?{??
  • ????return?parameterMappings;??
  • ??}??
  • ??
  • ??public?Object?getParameterObject()?{??
  • ????return?parameterObject;??
  • ??}??
  • ??
  • ??public?boolean?hasAdditionalParameter(String?name)?{??
  • ????return?metaParameters.hasGetter(name);??
  • ??}??
  • ??
  • ??public?void?setAdditionalParameter(String?name,?Object?value)?{??
  • ????metaParameters.setValue(name,?value);??
  • ??}???
  • ??
  • ??public?Object?getAdditionalParameter(String?name)?{??
  • ????return?metaParameters.getValue(name);???
  • ??}??
  • }??
  • ??????
  • SqlBound代碼并不多,就是一個普通的java對象,有兩個屬性非常重要
  • sql:看代碼里的注解,這個sql已經是經過了一些處理,可以被jdbc執行的了。xml里配置的sql可能有占位符#{username},這里的sql占位符已經被替換成"?"號了。
  • parameterMappings:執行sql對象的實際的參數。由此可以判斷,每執行一條sql都會創建一個BoundSql對象。
  • SqlSource和BoundSql本身并不復雜,復雜的是這兩個對象被創建的過程。

    LanguageDriver

    SqlSource對象是通過LanguageDriver對象構建的,在mapper.xml配置sql里可以通過lang屬性指定一個 LanguageDriver,但我們通常不會這樣子做。當lang屬性沒有配置時,Mybatis會屬性默認給一個。這個默認的 LanguageDriver在Configuration的構造方法中定義的: [java] view plain copy
  • public?Configuration()?{??
  • ????...??
  • ????languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);??
  • ????languageRegistry.register(RawLanguageDriver.class);??
  • ??}??
  • 馬上來看XMLLanguageDriver.createSqlSource()方法 [java] view plain copy
  • public?SqlSource?createSqlSource(Configuration?configuration,?XNode?script,?Class<?>?parameterType)?{??
  • ????XMLScriptBuilder?builder?=?new?XMLScriptBuilder(configuration,?script,?parameterType);??
  • ????return?builder.parseScriptNode();??
  • ??}??
  • XMLScriptBuilder

    XMLScriptBuilder.parseScriptNode()方法 [java] view plain copy
  • public?SqlSource?parseScriptNode()?{??
  • ????//將一個sql內容解析成多個SqlNode??
  • ????List<SqlNode>?contents?=?parseDynamicTags(context);??
  • ????//將多個SqlNode組合一個SqlNode??
  • ????MixedSqlNode?rootSqlNode?=?new?MixedSqlNode(contents);??
  • ????SqlSource?sqlSource?=?null;??
  • ????//判斷sql是否是動態的??
  • ????if?(isDynamic)?{??
  • ??????//生成動態的SqlSource??
  • ??????sqlSource?=?new?DynamicSqlSource(configuration,?rootSqlNode);??
  • ????}?else?{??
  • ??????//生成靜態的SqlSource??
  • ??????sqlSource?=?new?RawSqlSource(configuration,?rootSqlNode,?parameterType);??
  • ????}??
  • ????return?sqlSource;??
  • ??}??

  • 再看parseDynamicTagS(context)方法 [java] view plain copy
  • private?List<SqlNode>?parseDynamicTags(XNode?node)?{??
  • ????//一個sql會被解析成多個SqlNode,稍后會有示例詳細說明??
  • ????List<SqlNode>?contents?=?new?ArrayList<SqlNode>();??
  • ????NodeList?children?=?node.getNode().getChildNodes();??
  • ????for?(int?i?=?0;?i?<?children.getLength();?i++)?{??
  • ??????XNode?child?=?node.newXNode(children.item(i));??
  • ??????if?(child.getNode().getNodeType()?==?Node.CDATA_SECTION_NODE?||?child.getNode().getNodeType()?==?Node.TEXT_NODE)?{??
  • ????????//如果這個Node只包含文本??
  • ????????String?data?=?child.getStringBody("");??
  • ????????//生成一個TextSqlNode??
  • ????????TextSqlNode?textSqlNode?=?new?TextSqlNode(data);??
  • ????????//判斷是否是動態的,如果文本里包含占位符,如#{username}或{table_name},isDynamic()方法就會返回true??
  • ????????if?(textSqlNode.isDynamic())?{??
  • ??????????contents.add(textSqlNode);??
  • ??????????isDynamic?=?true;??
  • ????????}?else?{??
  • ??????????contents.add(new?StaticTextSqlNode(data));??
  • ????????}??
  • ??????}?else?if?(child.getNode().getNodeType()?==?Node.ELEMENT_NODE)?{?//?issue?#628??
  • ????????//如果是有xml標簽的Node,交由Handler處理,同時被認為是動態的??
  • ????????String?nodeName?=?child.getNode().getNodeName();??
  • ????????NodeHandler?handler?=?nodeHandlers.get(nodeName);??
  • ????????if?(handler?==?null)?{??
  • ??????????throw?new?BuilderException("Unknown?element?<"?+?nodeName?+?">?in?SQL?statement.");??
  • ????????}??
  • ????????handler.handleNode(child,?contents);??
  • ??????
  • ????????isDynamic?=?true;??
  • ??????}??
  • ????}??
  • ????return?contents;??
  • ??}??

  • 再看看nodeHandlers都有那些 [java] view plain copy
  • private?Map<String,?NodeHandler>?nodeHandlers?=?new?HashMap<String,?NodeHandler>()?{??
  • ????private?static?final?long?serialVersionUID?=?7123056019193266281L;??
  • ??
  • ????{??
  • ??????//Mybatis3動態sql都支持那些配置,這里就很清楚啦??
  • ??????put("trim",?new?TrimHandler());??
  • ??????put("where",?new?WhereHandler());??
  • ??????put("set",?new?SetHandler());??
  • ??????put("foreach",?new?ForEachHandler());??
  • ??????put("if",?new?IfHandler());??
  • ??????put("choose",?new?ChooseHandler());??
  • ??????put("when",?new?IfHandler());??
  • ??????put("otherwise",?new?OtherwiseHandler());??
  • ??????put("bind",?new?BindHandler());??
  • ????}??
  • ??};??

  • 看到這里基本上能了解sql是怎么被解析的啦!舉例說明: [html] view plain copy
  • <select?id="selectUserDetail"?resultMap="detailUserResultMap">??
  • ????????<![CDATA[?
  • ????????????select?user_id,user_name,user_type,cust_id?--這里一行會解析成一個StaticTextSqlNode?
  • ????????????????from?tf_f_user?a?--這里一行也會解析成一個StaticTextSqlNode?
  • ????????????????where?a.user_id=#{userId}?--這行會被解析成TextSqlNode,并且isDynamic被設置成true,因為有占位符?
  • ??????????????????????????????????????????--這個空行也解析成一個StaticTextSqlNode?
  • ????????]]><!--?這四個SqlNode會被組合成一個MixedSqlNode?-->??
  • ????</select>??

  • 再來個動態sql的: [html] view plain copy
  • <select?id="selectUserDetail"?resultMap="detailUserResultMap">??
  • ????????<![CDATA[?
  • ????????????select?user_id,user_name,user_type,cust_id?--這里一行會解析成一個StaticTextSqlNode?
  • ????????????????from?tf_f_user?a?--這里一行也會解析成一個StaticTextSqlNode?
  • ????????????????where?a.user_id=#{userId}?--這行會被解析成TextSqlNode,并且isDynamic被設置成true,因為有占位符?
  • ??????????????????????????????????????????--這個空行也解析成一個StaticTextSqlNode?
  • ????????]]>??
  • ????????<if?test="user_name!=null">?<!--?這個標簽里的內容會交給IfHandler處理?-->??
  • ????????????and?--這里的解析與上行的一樣,解析成一個StaticTextSqlNode??
  • ????????????user_name=#{userName}?--這里的解析與上行的一樣,也會被解析成一個TextSqlNode,并且isDynamic被設置成true,因為有占位符??
  • ????????</if><!--?IfHandler會將這里面的內個SqlNode組成MixedSqlNode再組成一個IfSqlNode?-->??
  • ????</select><!--?這五個SqlNode會被組合成一個MixedSqlNode?-->??

  • 附上IfHandler的代碼 [java] view plain copy
  • private?class?IfHandler?implements?NodeHandler?{??
  • ????public?void?handleNode(XNode?nodeToHandle,?List<SqlNode>?targetContents)?{??
  • ??????//解析子節點??
  • ??????List<SqlNode>?contents?=?parseDynamicTags(nodeToHandle);??
  • ??????//組合??
  • ??????MixedSqlNode?mixedSqlNode?=?new?MixedSqlNode(contents);??
  • ??????String?test?=?nodeToHandle.getStringAttribute("test");??
  • ??????//生成IfSqlNode??
  • ??????IfSqlNode?ifSqlNode?=?new?IfSqlNode(mixedSqlNode,?test);??
  • ??????targetContents.add(ifSqlNode);??
  • ????}??
  • ??}??

  • 其他的nodeHandler在這里就不討論了,實現方式與IfHandler差不多。如下兩個方法也不在這里做討論
  • SqlSource.getBoundSql()方法
  • SqlNode.apply(DynamicContextcontext)方法
  • ?

    http://blog.csdn.net/ashan_li/article/details/50351080

    轉載于:https://my.oschina.net/xiaominmin/blog/1599100

    總結

    以上是生活随笔為你收集整理的Mybatis3源码分析(05)-加载Configuration-加载MappedStatement的全部內容,希望文章能夠幫你解決所遇到的問題。

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