# 精尽 MyBatis 源码分析 —— MyBatis 初始化(三)之加载 Statement 配置 # 1. 概述 本文接 [《精尽 MyBatis 源码分析 —— MyBatis 初始化(二)之加载 Mapper 映射配置文件》](http://svip.iocoder.cn/MyBatis/builder-package-2) 一文,来分享 MyBatis 初始化的第三步,**加载 Statement 配置**。而这个步骤的入口是 XMLStatementBuilder 。下面,我们一起来看看它的代码实现。 在 [《精尽 MyBatis 源码分析 —— MyBatis 初始化(二)之加载 Mapper 映射配置文件》](http://svip.iocoder.cn/MyBatis/builder-package-2) 的 [「2.3.5 buildStatementFromContext」](https://svip.iocoder.cn/MyBatis/builder-package-3/#) 中,我们已经看到对 XMLStatementBuilder 的调用代码。代码如下: ``` // XMLMapperBuilder.java private void buildStatementFromContext(List list) { if (configuration.getDatabaseId() != null) { buildStatementFromContext(list, configuration.getDatabaseId()); } buildStatementFromContext(list, null); // 上面两块代码,可以简写成 buildStatementFromContext(list, configuration.getDatabaseId()); } private void buildStatementFromContext(List list, String requiredDatabaseId) { // <1> 遍历 `、``、``、`` 标签。 ## 2.1 构造方法 ``` // XMLStatementBuilder.java private final MapperBuilderAssistant builderAssistant; /** * 当前 XML 节点,例如: SELECT * FROM subject ``` - 方法参数 `included` ,是否**正在**处理 `` 标签中。😈 一脸懵逼?不要方,继续往下看。 - 在上述示例的 ``` select , from some_table t1 cross join some_table t2 ``` # 4. MapperBuilderAssistant ## 4.1 addMappedStatement `#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)` 方法,构建 MappedStatement 对象。代码如下: ``` // MapperBuilderAssistant.java 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) { // <1> 如果只想的 Cache 未解析,抛出 IncompleteElementException 异常 if (unresolvedCacheRef) { throw new IncompleteElementException("Cache-ref not yet resolved"); } // <2> 获得 id 编号,格式为 `${namespace}.${id}` id = applyCurrentNamespace(id, false); boolean isSelect = sqlCommandType == SqlCommandType.SELECT; // <3> 创建 MappedStatement.Builder 对象 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)) // <3.1> 获得 ResultMap 集合 .resultSetType(resultSetType) .flushCacheRequired(valueOrDefault(flushCache, !isSelect)) .useCache(valueOrDefault(useCache, isSelect)) .cache(currentCache); // <3.2> 获得 ParameterMap ,并设置到 MappedStatement.Builder 中 ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id); if (statementParameterMap != null) { statementBuilder.parameterMap(statementParameterMap); } // <4> 创建 MappedStatement 对象 MappedStatement statement = statementBuilder.build(); // <5> 添加到 configuration 中 configuration.addMappedStatement(statement); return statement; } ``` - `<1>` 处,如果只想的 Cache 未解析,抛出 IncompleteElementException 异常。 - `<2>` 处,获得 `id` 编号,格式为 `${namespace}.${id}` 。 - ``` <3> ``` 处,创建 MappedStatement.Builder 对象。详细解析,见 「4.1.3 MappedStatement」 。 - `<3.1>` 处,调用 `#getStatementResultMaps(...)` 方法,获得 ResultMap 集合。详细解析,见 [「4.1.3 getStatementResultMaps」](https://svip.iocoder.cn/MyBatis/builder-package-3/#) 。 - `<3.2>` 处,调用 `#getStatementParameterMap(...)` 方法,获得 ParameterMap ,并设置到 MappedStatement.Builder 中。详细解析,见 [4.1.4 getStatementResultMaps」](https://svip.iocoder.cn/MyBatis/builder-package-3/#) 。 - `<4>` 处,创建 MappedStatement 对象。详细解析,见 [「4.1.1 MappedStatement」](https://svip.iocoder.cn/MyBatis/builder-package-3/#) 。 - `<5>` 处,调用 `Configuration#addMappedStatement(statement)` 方法,添加到 `configuration` 中。代码如下: ``` // Configuration.java /** * MappedStatement 映射 * * KEY:`${namespace}.${id}` */ protected final Map mappedStatements = new StrictMap<>("Mapped Statements collection"); public void addMappedStatement(MappedStatement ms) { mappedStatements.put(ms.getId(), ms); } ``` ### 4.1.1 MappedStatement `org.apache.ibatis.mapping.MappedStatement` ,映射的语句,每个 `