该过程由XMLMapperBuilder的configurationElement方法触发:
XMLMapperBuilder
private void configurationElement(XNode context) {try {//获取mapper节点的namespace属性String namespace = context.getStringAttribute("namespace");if (namespace == null || namespace.equals("")) {throw new BuilderException("Mapper's namespace cannot be empty");}//设置builderAssistant的namespace属性builderAssistant.setCurrentNamespace(namespace);//解析cache-ref节点cacheRefElement(context.evalNode("cache-ref"));//重点分析 :解析cache节点----------------1-------------------cacheElement(context.evalNode("cache"));//解析parameterMap节点(已废弃)parameterMapElement(context.evalNodes("/mapper/parameterMap"));//重点分析 :解析resultMap节点(基于数据结果去理解)----------------2-------------------resultMapElements(context.evalNodes("/mapper/resultMap"));//解析sql节点sqlElement(context.evalNodes("/mapper/sql"));//重点分析 :解析select、insert、update、delete节点 ----------------3-------------------buildStatementFromContext(context.evalNodes("select|insert|update|delete"));} catch (Exception e) {throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);}}
调用buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
XMLMapperBuilder
//解析select、insert、update、delete节点private void buildStatementFromContext(List<XNode> list) {if (configuration.getDatabaseId() != null) {buildStatementFromContext(list, configuration.getDatabaseId());}buildStatementFromContext(list, null);}
调用private void buildStatementFromContext(List list, String requiredDatabaseId)
XMLMapperBuilder
//处理所有的sql语句节点并注册至configuration对象private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {for (XNode context : list) {//创建XMLStatementBuilder 专门用于解析sql语句节点final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);try {//解析sql语句节点statementParser.parseStatementNode();} catch (IncompleteElementException e) {configuration.addIncompleteStatement(statementParser);}}}
该方法新建XMLStatementBuilder对象,对象构建过程:
首先XMLStatementBuilder类继承于BaseBuilder,与XMLStatementBuilder、XMLConfigBuilder一样调用BaseBuilder构造方法,初始化属性configuration、typeAliasRegistry、typeHandlerRegistry值。
然后初始化builderAssistant(该属性的值由XMLMapperBuilder传入,首次赋值在XMLMapperBuilder构造方法中)、context、requiredDatabaseId属性值。
XMLStatementBuilder对象初始化完成后,执行statementParser.parseStatementNode();解析过程:
XMLStatementBuilder
public void parseStatementNode() {//获取sql节点的idString id = context.getStringAttribute("id");String databaseId = context.getStringAttribute("databaseId");if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {return;}/*获取sql节点的各种属性*/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");StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);//根据sql节点的名称获取SqlCommandType(INSERT, UPDATE, DELETE, SELECT)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//在解析sql语句之前先解析<include>节点XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);includeParser.applyIncludes(context.getNode());// Parse selectKey after includes and remove them.//在解析sql语句之前,处理<selectKey>子节点,并在xml节点中删除processSelectKeyNodes(id, parameterTypeClass, langDriver);// Parse the SQL (pre: <selectKey> and <include> were parsed and removed)//解析sql语句是解析mapper.xml的核心,实例化sqlSource,使用sqlSource封装sql语句SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);String resultSets = context.getStringAttribute("resultSets");//获取resultSets属性String keyProperty = context.getStringAttribute("keyProperty");//获取主键信息keyPropertyString keyColumn = context.getStringAttribute("keyColumn");///获取主键信息keyColumn//根据<selectKey>获取对应的SelectKeyGenerator的idKeyGenerator keyGenerator;String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);//获取keyGenerator对象,如果是insert类型的sql语句,会使用KeyGenerator接口获取数据库生产的id;if (configuration.hasKeyGenerator(keyStatementId)) {keyGenerator = configuration.getKeyGenerator(keyStatementId);} else {keyGenerator = context.getBooleanAttribute("useGeneratedKeys",configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;}//通过builderAssistant实例化MappedStatement,并注册至configuration对象builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);}
通过MapperBuilderAssistant实例化MappedStatement,并注册至configuration对象
MapperBuilderAssistant
public MappedStatement addMappedStatement(String id,SqlSource sqlSource,StatementType statementType,SqlCommandType sqlCommandType,Integer fetchSize,Integer timeout,String parameterMap,Class<?> parameterType,String resultMap,Class<?> resultType,ResultSetType resultSetType,boolean flushCache,boolean useCache,boolean resultOrdered,KeyGenerator keyGenerator,String keyProperty,String keyColumn,String databaseId,LanguageDriver lang,String resultSets) {if (unresolvedCacheRef) {throw new IncompleteElementException("Cache-ref not yet resolved");}id = applyCurrentNamespace(id, false);boolean isSelect = sqlCommandType == SqlCommandType.SELECT;MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType).resource(resource).fetchSize(fetchSize).timeout(timeout).statementType(statementType).keyGenerator(keyGenerator).keyProperty(keyProperty).keyColumn(keyColumn).databaseId(databaseId).lang(lang).resultOrdered(resultOrdered).resultSets(resultSets).resultMaps(getStatementResultMaps(resultMap, resultType, id)).resultSetType(resultSetType).flushCacheRequired(valueOrDefault(flushCache, !isSelect)).useCache(valueOrDefault(useCache, isSelect)).cache(currentCache);ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);if (statementParameterMap != null) {statementBuilder.parameterMap(statementParameterMap);}MappedStatement statement = statementBuilder.build();configuration.addMappedStatement(statement);return statement;}
此处可以看到,MappedStatement中使用了MapperBuilderAssistant对象的currentCache(二级缓存)。
在MappedStatement.Builder构建过程中,
.flushCacheRequired(valueOrDefault(flushCache, !isSelect)
此处flushCache的值表明了是否需要清除一级缓存。默认查询的时候,不需要清除,其他操作都要清除。在分布式系统中,若需要清控一级缓存,则配置flushCache为true即可。效果上相当于关闭了该sql的一级缓存。