日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

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

發(fā)布時(shí)間:2025/6/15 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mybatis3源码分析(05)-加载Configuration-加载MappedStatement 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

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

MappedStatement說明

一個(gè)MappedStatement對(duì)象對(duì)應(yīng)Mapper配置文件中的一個(gè)select/update/insert/delete節(jié)點(diǎn),主要描述的是一條SQL語句。其屬性有 [java] view plain copy
  • //節(jié)點(diǎn)中的id屬性加要命名空間??
  • private?String?id;??
  • //直接從節(jié)點(diǎn)屬性中取??
  • private?Integer?fetchSize;??
  • //直接從節(jié)點(diǎn)屬性中取??
  • private?Integer?timeout;??
  • private?StatementType?statementType;??
  • private?ResultSetType?resultSetType;??
  • //對(duì)應(yīng)一條SQL語句??
  • private?SqlSource?sqlSource;??
  • ??
  • //每條語句都對(duì)就一個(gè)緩存,如果有的話。??
  • private?Cache?cache;??
  • //這個(gè)已經(jīng)過時(shí)了??
  • 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;??
  • ??
  • //是否有內(nèi)映射??
  • private?boolean?hasNestedResultMaps;??
  • private?String?databaseId;??
  • private?Log?statementLog;??
  • private?LanguageDriver?lang;??
  • private?String[]?resultSets;??

  • 上面屬性都比較簡(jiǎn)單,復(fù)雜的是SqlSource,下面有詳細(xì)的描述!

    XMLStatementBuilder.parseStatementNode()方法

    resultMap元素的解析已經(jīng)分析完畢。與resultMap不一樣,XmlMapperBuilder在解析select/update /insert/delete的元素時(shí)會(huì)創(chuàng)建一個(gè)XMLStatementBuilder對(duì)象,解析的工作交由其方法 parseStatementNode()方法完成。 [java] view plain copy
  • private?void?buildStatementFromContext(List<XNode>?list,?String?requiredDatabaseId)?{??
  • ????for?(XNode?context?:?list)?{??
  • ??????//一個(gè)select/update/insert/delete元素創(chuàng)建一個(gè)XMLStatementBuilder對(duì)象??
  • ??????final?XMLStatementBuilder?statementParser?=?new?XMLStatementBuilder(configuration,?builderAssistant,?context,?requiredDatabaseId);??
  • ??????try?{??
  • ????????//將元素解析成MappedStatemenet對(duì)象,并加入到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的類型,對(duì)應(yīng)jdbc里的三個(gè)類型:Statement、PreparedStatement、CallableStatement,默認(rèn)使用PreparedStatement??
  • ????StatementType?statementType?=?StatementType.valueOf(context.getStringAttribute("statementType",?StatementType.PREPARED.toString()));??
  • ????//這個(gè)也是跟jdbc里相對(duì)應(yīng)的,一般采用默認(rèn)即可??
  • ????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對(duì)象,這個(gè)對(duì)象非常重要,接下來詳細(xì)分析??
  • ????//?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");??
  • ??????
  • ????//自動(dòng)生成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對(duì)象,并加到Configuration中??
  • ????builderAssistant.addMappedStatement(id,?sqlSource,?statementType,?sqlCommandType,??
  • ????????fetchSize,?timeout,?parameterMap,?parameterTypeClass,?resultMap,?resultTypeClass,??
  • ????????resultSetTypeEnum,?flushCache,?useCache,?resultOrdered,???
  • ????????keyGenerator,?keyProperty,?keyColumn,?databaseId,?langDriver,?resultSets);??
  • ??}??
  • 上在方法里附件解析一些基本的屬性外還有兩個(gè)主要的部分
  • SqlSource的構(gòu)建過程
    [java] view plain copy
  • SqlSource?sqlSource?=?langDriver.createSqlSource(configuration,?context,?parameterTypeClass);??
  • MappedStatement的構(gòu)建過程 [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構(gòu)建過程

    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內(nèi)容,該sql一般還不能都被直接執(zhí)行,例如 [html] view plain copy
  • <select?id="selectUserDetail"?resultMap="detailUserResultMap">??
  • ????<!--CDATA里內(nèi)容會(huì)都解析成一個(gè)SqlSource對(duì)象-->??
  • ????????????????<![CDATA[?
  • ????????????select?user_id,user_name,user_type,cust_id?from?tf_f_user?a?where?a.user_id=#${userId}?
  • ????????]]>/select>??
  • SqlSource只有一個(gè)方法:getBoundSql(paramenterObject),其中paramenterObject為運(yùn)行sql里的實(shí)際參數(shù)

    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代碼并不多,就是一個(gè)普通的java對(duì)象,有兩個(gè)屬性非常重要
  • sql:看代碼里的注解,這個(gè)sql已經(jīng)是經(jīng)過了一些處理,可以被jdbc執(zhí)行的了。xml里配置的sql可能有占位符#{username},這里的sql占位符已經(jīng)被替換成"?"號(hào)了。
  • parameterMappings:執(zhí)行sql對(duì)象的實(shí)際的參數(shù)。由此可以判斷,每執(zhí)行一條sql都會(huì)創(chuàng)建一個(gè)BoundSql對(duì)象。
  • SqlSource和BoundSql本身并不復(fù)雜,復(fù)雜的是這兩個(gè)對(duì)象被創(chuàng)建的過程。

    LanguageDriver

    SqlSource對(duì)象是通過LanguageDriver對(duì)象構(gòu)建的,在mapper.xml配置sql里可以通過lang屬性指定一個(gè) LanguageDriver,但我們通常不會(huì)這樣子做。當(dāng)lang屬性沒有配置時(shí),Mybatis會(huì)屬性默認(rèn)給一個(gè)。這個(gè)默認(rèn)的 LanguageDriver在Configuration的構(gòu)造方法中定義的: [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()?{??
  • ????//將一個(gè)sql內(nèi)容解析成多個(gè)SqlNode??
  • ????List<SqlNode>?contents?=?parseDynamicTags(context);??
  • ????//將多個(gè)SqlNode組合一個(gè)SqlNode??
  • ????MixedSqlNode?rootSqlNode?=?new?MixedSqlNode(contents);??
  • ????SqlSource?sqlSource?=?null;??
  • ????//判斷sql是否是動(dòng)態(tài)的??
  • ????if?(isDynamic)?{??
  • ??????//生成動(dòng)態(tài)的SqlSource??
  • ??????sqlSource?=?new?DynamicSqlSource(configuration,?rootSqlNode);??
  • ????}?else?{??
  • ??????//生成靜態(tài)的SqlSource??
  • ??????sqlSource?=?new?RawSqlSource(configuration,?rootSqlNode,?parameterType);??
  • ????}??
  • ????return?sqlSource;??
  • ??}??

  • 再看parseDynamicTagS(context)方法 [java] view plain copy
  • private?List<SqlNode>?parseDynamicTags(XNode?node)?{??
  • ????//一個(gè)sql會(huì)被解析成多個(gè)SqlNode,稍后會(huì)有示例詳細(xì)說明??
  • ????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)?{??
  • ????????//如果這個(gè)Node只包含文本??
  • ????????String?data?=?child.getStringBody("");??
  • ????????//生成一個(gè)TextSqlNode??
  • ????????TextSqlNode?textSqlNode?=?new?TextSqlNode(data);??
  • ????????//判斷是否是動(dòng)態(tài)的,如果文本里包含占位符,如#{username}或{table_name},isDynamic()方法就會(huì)返回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標(biāo)簽的Node,交由Handler處理,同時(shí)被認(rèn)為是動(dòng)態(tài)的??
  • ????????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動(dòng)態(tài)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?--這里一行會(huì)解析成一個(gè)StaticTextSqlNode?
  • ????????????????from?tf_f_user?a?--這里一行也會(huì)解析成一個(gè)StaticTextSqlNode?
  • ????????????????where?a.user_id=#{userId}?--這行會(huì)被解析成TextSqlNode,并且isDynamic被設(shè)置成true,因?yàn)橛姓嘉环?
  • ??????????????????????????????????????????--這個(gè)空行也解析成一個(gè)StaticTextSqlNode?
  • ????????]]><!--?這四個(gè)SqlNode會(huì)被組合成一個(gè)MixedSqlNode?-->??
  • ????</select>??

  • 再來個(gè)動(dòng)態(tài)sql的: [html] view plain copy
  • <select?id="selectUserDetail"?resultMap="detailUserResultMap">??
  • ????????<![CDATA[?
  • ????????????select?user_id,user_name,user_type,cust_id?--這里一行會(huì)解析成一個(gè)StaticTextSqlNode?
  • ????????????????from?tf_f_user?a?--這里一行也會(huì)解析成一個(gè)StaticTextSqlNode?
  • ????????????????where?a.user_id=#{userId}?--這行會(huì)被解析成TextSqlNode,并且isDynamic被設(shè)置成true,因?yàn)橛姓嘉环?
  • ??????????????????????????????????????????--這個(gè)空行也解析成一個(gè)StaticTextSqlNode?
  • ????????]]>??
  • ????????<if?test="user_name!=null">?<!--?這個(gè)標(biāo)簽里的內(nèi)容會(huì)交給IfHandler處理?-->??
  • ????????????and?--這里的解析與上行的一樣,解析成一個(gè)StaticTextSqlNode??
  • ????????????user_name=#{userName}?--這里的解析與上行的一樣,也會(huì)被解析成一個(gè)TextSqlNode,并且isDynamic被設(shè)置成true,因?yàn)橛姓嘉环??
  • ????????</if><!--?IfHandler會(huì)將這里面的內(nèi)個(gè)SqlNode組成MixedSqlNode再組成一個(gè)IfSqlNode?-->??
  • ????</select><!--?這五個(gè)SqlNode會(huì)被組合成一個(gè)MixedSqlNode?-->??

  • 附上IfHandler的代碼 [java] view plain copy
  • private?class?IfHandler?implements?NodeHandler?{??
  • ????public?void?handleNode(XNode?nodeToHandle,?List<SqlNode>?targetContents)?{??
  • ??????//解析子節(jié)點(diǎn)??
  • ??????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在這里就不討論了,實(shí)現(xiàn)方式與IfHandler差不多。如下兩個(gè)方法也不在這里做討論
  • SqlSource.getBoundSql()方法
  • SqlNode.apply(DynamicContextcontext)方法
  • ?

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

    轉(zhuǎn)載于:https://my.oschina.net/xiaominmin/blog/1599100

    總結(jié)

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

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。