文章目录
加载过程
1、加载时机:项目启动实例化SqlSessionFactory时
项目初始化时,会实例化 SqlSessionFactory。实例化过程中,通过加载Xml mapper文件(利用XMLMapperBuilder对象),保存sql信息。
- com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration#sqlSessionFactory
- com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean#buildSqlSessionFactory
- com.baomidou.mybatisplus.core.MybatisConfiguration(存储被加载对象)
- org.apache.ibatis.builder.xml.XMLMapperBuilder
- org.apache.ibatis.builder.xml.XMLStatementBuilder
- org.apache.ibatis.builder.xml.XMLStatementBuilder#parseStatementNode
// com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean#buildSqlSessionFactory 片段
Resource[] var24 = this.mapperLocations;
int var27 = var24.length;
for(int var5 = 0; var5 < var27; ++var5) {// 遍历mapper路径下的所有XML Mapper文件
Resource mapperLocation = var24[var5];
if (mapperLocation != null) {
try {
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
xmlMapperBuilder.parse();// 解析XML Mapper
} catch (Exception var19) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", var19);
} finally {
ErrorContext.instance().reset();
}
LOGGER.debug(() -> {
return "Parsed mapper file: '" + mapperLocation + "'";
});
}
}
2、加载处理过程
循环加载、处理每个XML Mapper
// org.apache.ibatis.builder.xml.XMLMapperBuilder#parse
public void parse() {
if (!this.configuration.isResourceLoaded(this.resource)) {
// 加载XML Mapper文件内容
this.configurationElement(this.parser.evalNode("/mapper"));// 将XML 元素都转化到类中
this.configuration.addLoadedResource(this.resource);
this.bindMapperForNamespace();
}
// 处理加载后的XML Mapper信息
this.parsePendingResultMaps();
this.parsePendingCacheRefs();
this.parsePendingStatements();// 解析待处理statement,生成sql statement(不再包含 xml中的 sql引用关系)
}
1、加载的内容
- XML 的各种标签:org.apache.ibatis.builder.xml.XMLMapperBuilder#configurationElement
- 添加待处理缓存引用(cache-ref)
- 处理方法:org.apache.ibatis.builder.xml.XMLMapperBuilder#cacheRefElement
- 添加待处理结果集(/mapper/resultMap)
- 处理方法:org.apache.ibatis.builder.xml.XMLMapperBuilder#resultMapElements
-
添加待处理语句(select|insert|update|delete)
- 处理方法:org.apache.ibatis.builder.xml.XMLMapperBuilder#buildStatementFromContext(java.util.List<org.apache.ibatis.parsing.XNode>, java.lang.String)
- 其他标签:
- cache
- /mapper/parameterMap
-
/mapper/sql
- 存储到 org.apache.ibatis.builder.xml.XMLMapperBuilder#sqlFragments
- 若存在 SQL片段,一个SQL片段会对应生成两条记录:shortKey,namespace.shortKey
- org.apache.ibatis.session.Configuration.StrictMap#put
- 添加待处理缓存引用(cache-ref)
- 持久化XML Mapper的文件所在路径到内存中:
- org.apache.ibatis.session.Configuration#loadedResources
- 根据namespace,持久化XML Mapper与对应 Class类(Dao)的对应关系:org.apache.ibatis.builder.xml.XMLMapperBuilder#bindMapperForNamespace
- Class:org.apache.ibatis.session.Configuration#mapperRegistry
- “namespace:”+namespace:org.apache.ibatis.session.Configuration#loadedResources
2、对被加载内容的处理过程
存储被加载对象的内存对象:com.baomidou.mybatisplus.core.MybatisConfiguration
1、解析待处理结果集
- 处理方法:org.apache.ibatis.builder.xml.XMLMapperBuilder#parsePendingResultMaps
- org.apache.ibatis.builder.ResultMapResolver#resolve
- 处理内容:org.apache.ibatis.session.Configuration#incompleteResultMaps
- 结果:
- 从org.apache.ibatis.builder.MapperBuilderAssistant 的成员变量org.apache.ibatis.session.Configuration#resultMaps中获取元素对象org.apache.ibatis.mapping.ResultMap,
- 利用获取的对象信息,重新构造一个 org.apache.ibatis.mapping.ResultMap对象,
- 将新构造的对象,存储并覆盖到 org.apache.ibatis.builder.MapperBuilderAssistant 的成员变量org.apache.ibatis.session.Configuration#resultMaps 中
2、解析待处理缓存引用
- 处理方法:org.apache.ibatis.builder.xml.XMLMapperBuilder#parsePendingCacheRefs
- org.apache.ibatis.builder.CacheRefResolver#resolveCacheRef
- 处理内容:org.apache.ibatis.session.Configuration#incompleteCacheRefs
- 结果:
- 从org.apache.ibatis.builder.MapperBuilderAssistant 的成员变量org.apache.ibatis.session.Configuration#caches中获取元素对象org.apache.ibatis.cache.Cache,
- 将其存储到 org.apache.ibatis.builder.MapperBuilderAssistant#currentCache中
3、解析待处理语句
- 处理方法:org.apache.ibatis.builder.xml.XMLMapperBuilder#parsePendingStatements
- org.apache.ibatis.builder.xml.XMLStatementBuilder#parseStatementNode
- 处理内容:org.apache.ibatis.session.Configuration#incompleteStatements
- 结果:
- 构造 org.apache.ibatis.mapping.MappedStatement对象,
- 将其存储到 org.apache.ibatis.builder.MapperBuilderAssistant 的成员变量org.apache.ibatis.session.Configuration#mappedStatements中
注意点
SQL片段内,使用Include标签时,refid需指定被调用SQL片段的全限定名称(namespace.id)
对于使用“”元素定义的sql片段,若该片段与他的外层引用片段同属于一个命名空间namespace,则内层sql的引用必须使用全限定namespace
情景详解:
- AMapper.xml 中定义了两个sql片段,他们的id分别为:sqlOne, sqlTwo;
- 存在引用关系:sqlOne 中 使用“<include>”元素引用了 sqlTwo(由于处于同一个namespace中,使用的refid=“sql的id名”);
- BMapper.xml 中定义了一个“<select>”元素,且使用“<include>”元素引用了AMapper.xml中的id="sqlOne"的SQL片段(使用的refid=“namespace”+“.”+“sql的id名”);
此时,在BMapper.xml中,对于SQL片段“sqlTwo”,由于没有前缀namespace,就会默认为本namespace中的SQL片段,为之加上自己的namespace名,此时,就会找不到SQL片段,造成执行报错(找不到元素,无法转化xml为sql语句)