目录
1.1通过SqlSessionFactoryBuilder.buid获取
1.2 通过自定义构建Configuration对象构建SqlSessionFactory
一.生成SqlSessionFactory
在生成SqlSessionFactory主要是构建configuration核心配置类,该配置类贯穿着Mybatis几乎所有执行步骤,在大多数核心类里面几乎都存在,主要用于存放数据库环境,解析好的MapperProxyFactory(用户构建Mapper代理对象),interceptorChain拦截器,解析好的mappedStatements(用于对sql的描述),二级缓存caches(以名称空间确定使用的Cache,在使用中直接从MappedStatement中获取,在构建时通过MapperBuilderAssistant.useCacheRef(nameSpace)方法调用configuration.getCache(id)获取)等重要配置参数或者解析参数。
1.1通过SqlSessionFactoryBuilder.buid获取
// 1. 读取配置文件,读成字节输入流,注意:现在还没解析
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 2. 解析配置文件,封装Configuration对象 创建DefaultSqlSessionFactory对象
build方法通过调用 new DefaultSqlSessionFactory(config)构建;config类通过XMLConfigBuilder.parse进行构建,代码如下
// 创建 XMLConfigBuilder 对象
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
// 执行 XML 解析
// 创建 DefaultSqlSessionFactory 对象 parser.parse()解析xml配置文件
return build(parser.parse());
parse方法解析
//issue #117 read properties first
// 解析 <properties />
propertiesElement(root.evalNode("properties"));
// 解析 <settings />
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
// 解析 <typeAliases />
typeAliasesElement(root.evalNode("typeAliases"));
// 解析 <plugins />
pluginElement(root.evalNode("plugins"));
// 解析 <objectFactory />
objectFactoryElement(root.evalNode("objectFactory"));
// 解析 <objectWrapperFactory />
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// 解析 <reflectorFactory />
reflectorFactoryElement(root.evalNode("reflectorFactory"));
// 赋值 <settings />
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
// 解析 <environments />
environmentsElement(root.evalNode("environments"));
// 解析 <databaseIdProvider />
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
// 解析 <typeHandlers />
typeHandlerElement(root.evalNode("typeHandlers"));
// 解析 <mappers />解析成
mapperElement(root.evalNode("mappers"));
mapperElement方法通过调用configuration.addMappers(mapperPackage) ---> 调用configuration.addMappers(mapperPackage) =>调用mapperRegistry.addMappers(packageName)完成MapperProxyFactorymapper代理工厂添加和mapper接口类sql解析封装成MappedStatement
try {
// 添加到 knownMappers 中
knownMappers.put(type, new MapperProxyFactory<>(type));
// 解析 Mapper 的注解配置
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
// 标记加载完成
loadCompleted = true;
} finally {
// 若加载未完成,从 knownMappers 中移除
if (!loadCompleted) {
knownMappers.remove(type);
}
}
致此通过SQLSessionFactoryBuilder构建SqlSessionFactory完成
1.2 通过自定义构建Configuration对象构建SqlSessionFactory
具体可参考MybatisSqlSessionFactoryBean.buildSqlSessionFactory()或者SqlSessionFactoryBean.buildSqlSessionFactory方法完成构建具体以MybatisSqlSessionFactoryBean做解析
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
final MybatisConfiguration targetConfiguration;
//使用 MybatisXmlConfigBuilder 而不是 XMLConfigBuilder
MybatisXMLConfigBuilder xmlConfigBuilder = null;
if (this.configuration != null) {
targetConfiguration = this.configuration;
if (targetConfiguration.getVariables() == null) {
targetConfiguration.setVariables(this.configurationProperties);
} else if (this.configurationProperties != null) {
targetConfiguration.getVariables().putAll(this.configurationProperties);
}
} else if (this.configLocation != null) {
// TODO 使用 MybatisXMLConfigBuilder
xmlConfigBuilder = new MybatisXMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
targetConfiguration = xmlConfigBuilder.getConfiguration();
} else {
LOGGER.debug(() -> "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
// TODO 使用 MybatisConfiguration
targetConfiguration = new MybatisConfiguration();
Optional.ofNullable(this.configurationProperties).ifPresent(targetConfiguration::setVariables);
}
// TODO 无配置启动所必须的
this.globalConfig = Optional.ofNullable(this.globalConfig).orElseGet(GlobalConfigUtils::defaults);
this.globalConfig.setDbConfig(Optional.ofNullable(this.globalConfig.getDbConfig()).orElseGet(GlobalConfig.DbConfig::new));
// TODO 初始化 id-work 以及 打印骚东西
targetConfiguration.setGlobalConfig(this.globalConfig);
// TODO 自定义枚举类扫描处理
if (hasLength(this.typeEnumsPackage)) {
Set<Class<?>> classes;
if (typeEnumsPackage.contains(StringPool.STAR) && !typeEnumsPackage.contains(StringPool.COMMA)
&& !typeEnumsPackage.contains(StringPool.SEMICOLON)) {
classes = scanClasses(typeEnumsPackage, null);
if (classes.isEmpty()) {
LOGGER.warn(() -> "Can't find class in '[" + typeEnumsPackage + "]' package. Please check your configuration.");
}
} else {
classes = new HashSet<>();
String[] typeEnumsPackageArray = tokenizeToStringArray(this.typeEnumsPackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Assert.notNull(typeEnumsPackageArray, "not find typeEnumsPackage:" + typeEnumsPackage);
Stream.of(typeEnumsPackageArray).forEach(typePackage -> {
try {
Set<Class<?>> scanTypePackage = scanClasses(typePackage, null);
if (scanTypePackage.isEmpty()) {
LOGGER.warn(() -> "Can't find class in '[" + typePackage + "]' package. Please check your configuration.");
} else {
classes.addAll(scanTypePackage);
}
} catch (IOException e) {
throw new MybatisPlusException("Cannot scan class in '[" + typePackage + "]' package", e);
}
});
}
// 取得类型转换注册器
TypeHandlerRegistry typeHandlerRegistry = targetConfiguration.getTypeHandlerRegistry();
classes.stream()
.filter(Class::isEnum)
.filter(cls -> IEnum.class.isAssignableFrom(cls) || MybatisEnumTypeHandler.dealEnumType(cls).isPresent())
.forEach(cls -> typeHandlerRegistry.register(cls, MybatisEnumTypeHandler.class));
}
Optional.ofNullable(this.objectFactory).ifPresent(targetConfiguration::setObjectFactory);
Optional.ofNullable(this.objectWrapperFactory).ifPresent(targetConfiguration::setObjectWrapperFactory);
Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);
if (hasLength(this.typeAliasesPackage)) {
scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream()
.filter(clazz -> !clazz.isAnonymousClass()).filter(clazz -> !clazz.isInterface())
.filter(clazz -> !clazz.isMemberClass()).forEach(targetConfiguration.getTypeAliasRegistry()::registerAlias);
}
if (!isEmpty(this.typeAliases)) {
Stream.of(this.typeAliases).forEach(typeAlias -> {
targetConfiguration.getTypeAliasRegistry().registerAlias(typeAlias);
LOGGER.debug(() -> "Registered type alias: '" + typeAlias + "'");
});
}
if (!isEmpty(this.plugins)) {
Stream.of(this.plugins).forEach(plugin -> {
targetConfiguration.addInterceptor(plugin);
LOGGER.debug(() -> "Registered plugin: '" + plugin + "'");
});
}
if (hasLength(this.typeHandlersPackage)) {
scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter(clazz -> !clazz.isAnonymousClass())
.filter(clazz -> !clazz.isInterface()).filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
.filter(clazz -> ClassUtils.getConstructorIfAvailable(clazz) != null)
.forEach(targetConfiguration.getTypeHandlerRegistry()::register);
}
if (!isEmpty(this.typeHandlers)) {
Stream.of(this.typeHandlers).forEach(typeHandler -> {
targetConfiguration.getTypeHandlerRegistry().register(typeHandler);
LOGGER.debug(() -> "Registered type handler: '" + typeHandler + "'");
});
}
if (!isEmpty(this.scriptingLanguageDrivers)) {
Stream.of(this.scriptingLanguageDrivers).forEach(languageDriver -> {
targetConfiguration.getLanguageRegistry().register(languageDriver);
LOGGER.debug(() -> "Registered scripting language driver: '" + languageDriver + "'");
});
}
Optional.ofNullable(this.defaultScriptingLanguageDriver).ifPresent(targetConfiguration::setDefaultScriptingLanguage);
if (this.databaseIdProvider != null) {//fix #64 set databaseId before parse mapper xmls
try {
targetConfiguration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
} catch (SQLException e) {
throw new NestedIOException("Failed getting a databaseId", e);
}
}
Optional.ofNullable(this.cache).ifPresent(targetConfiguration::addCache);
if (xmlConfigBuilder != null) {
try {
xmlConfigBuilder.parse();
LOGGER.debug(() -> "Parsed configuration file: '" + this.configLocation + "'");
} catch (Exception ex) {
throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
} finally {
ErrorContext.instance().reset();
}
}
targetConfiguration.setEnvironment(new Environment(MybatisSqlSessionFactoryBean.class.getSimpleName(),
this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory,
this.dataSource));
//解析mapperLocations配置mybatis原生框架不支持改方式解析是通过Mappers 对mapper接口进行解析,反推mapper接口对应的xml文件进行解析
//对mybatis来说mapper接口与xml没有直接的绑定,是通过method构建成statementId然后通过configuration缓存statement的map中获取
//具体映射可参考mapperProxyFactory类的newInstance方法 =>new MapperProxy<>(sqlSession, mapperInterface, methodCache) =>
// invoke => cachedMapperMethod(Method method) => new MapperMethod(mapperInterface, method, sqlSession.getConfiguration())
// => this.command = new SqlCommand(config, mapperInterface, method);
// this.method = new MethodSignature(config, mapperInterface, method);
// => resolveMappedStatement(mapperInterface, methodName, declaringClass,configuration)绑定xml方法
if (this.mapperLocations != null) {
if (this.mapperLocations.length == 0) {
LOGGER.warn(() -> "Property 'mapperLocations' was specified but matching resources are not found.");
} else {
for (Resource mapperLocation : this.mapperLocations) {
if (mapperLocation == null) {
continue;
}
try {
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
xmlMapperBuilder.parse();
} catch (Exception e) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
} finally {
ErrorContext.instance().reset();
}
LOGGER.debug(() -> "Parsed mapper file: '" + mapperLocation + "'");
}
}
} else {
LOGGER.debug(() -> "Property 'mapperLocations' was not specified.");
}
final SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(targetConfiguration);
// TODO SqlRunner
SqlHelper.FACTORY = sqlSessionFactory;
// TODO 打印骚东西 Banner
if (globalConfig.isBanner()) {
System.out.println(" _ _ |_ _ _|_. ___ _ | _ ");
System.out.println("| | |\\/|_)(_| | |_\\ |_)||_|_\\ ");
System.out.println(" / | ");
System.out.println(" " + MybatisPlusVersion.getVersion() + " ");
}
return sqlSessionFactory;
}
致此通过直接构建configuration类完成sqlSessionFactory构建
二.构建Sqlsession
获取sqlsession
SqlSession sqlSession = sqlSessionFactory.openSession();
public SqlSession openSession() {
//getDefaultExecutorType()传递的是SimpleExecutor
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
/**
* @param execType 执行器类型
* @param level 事务隔离级别
* @param autoCommit 是否自动提交事务
* @return SQLSession
*/
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 获得 Environment 对象
final Environment environment = configuration.getEnvironment();
// 创建 Transaction 对象
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 创建 Executor 对象 在此方法涉及mybatis插件 通过轮流调用Interceptor.plugin方法完成代理拦截符合条件的方法,将方法,拦截对象,
// 方法参数封装成invocation传入intercept方法供用户完成插件逻辑
final Executor executor = configuration.newExecutor(tx, execType);
// 创建 DefaultSqlSession 对象
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
//则关闭 事务
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
创建执行器Executor
/**
* 创建 Executor 对象
*
* @param transaction 事务对象
* @param executorType 执行器类型
* @return Executor 对象
*/
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
// 获得执行器类型
executorType = executorType == null ? defaultExecutorType : executorType; // 使用默认
executorType = executorType == null ? ExecutorType.SIMPLE : executorType; // 使用 ExecutorType.SIMPLE
// 创建对应实现的 Executor 对象
Executor executor;
if (ExecutorType.BATCH == executorType) {
//批量执行执行器
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
//重用StatementHandler
executor = new ReuseExecutor(this, transaction);
} else {
//简单执行器
executor = new SimpleExecutor(this, transaction);
}
// 如果开启缓存,创建缓存执行器,内部通过对executor进行包装,查询数据时二级缓存不存在时通过executor完成crud
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 应用插件
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
致此执行器创建完毕然后通过DefaultSqlSession构造方法创建SqlSession致此SqlSession创建完成
三.获取mapper代理对象
sqlSession.getMapper(Mapper.class);
从configuration中获取mapper,可以看出configuration的作用有多重要
@Override
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
从MapperRegistry中获取
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
生成mapper的代理对象
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 获得 MapperProxyFactory 对象,回想前面的存入MapperProxyFactory对象
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
// 不存在,则抛出 BindingException 异常
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
/// 通过动态代理工厂生成实例。
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
在newInstance方法中完成对mapper方法的代理
public T newInstance(SqlSession sqlSession) {
// 创建了JDK动态代理的invocationHandler接口的实现类mapperProxy,传入methodCache是为了
// 对解析后的MapperMethod做缓存方便后面使用的时候直接获取,通过execute方法传入
// sqlsession直接执行,解析实在invoke代理方法中执行
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
// 调用了重载方法
return newInstance(mapperProxy);
}
MapperProxy的代理逻辑invoke方法解析
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 如果是 Object 定义的方法,直接调用
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
// 获得 MapperMethod 对象,并缓存
// 该方法通过MapperMethod 的构造方法以及MethodSignature构造方法
// 完成对方法command以及MethodSignature的解析,然后封装成MapperMethod对象
// 通过调用execute方法,进入sqlsession查询步骤
final MapperMethod mapperMethod = cachedMapperMethod(method);
// 重点在这:MapperMethod最终调用了执行的方法
return mapperMethod.execute(sqlSession, args);
}
new SqlCommand(config, mapperInterface, method)方法解析
public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
final String methodName = method.getName();
final Class<?> declaringClass = method.getDeclaringClass();
// 获得 MappedStatement 对象
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
if (ms == null) {
if (method.getAnnotation(Flush.class) != null) {
name = null;
type = SqlCommandType.FLUSH;
} else {
throw new BindingException("Invalid bound statement (not found): "
+ mapperInterface.getName() + "." + methodName);
}
} else {
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}
new MethodSignature(config, mapperInterface, method)
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
if (resolvedReturnType instanceof Class<?>) {
this.returnType = (Class<?>) resolvedReturnType;
} else if (resolvedReturnType instanceof ParameterizedType) {
this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
} else {
this.returnType = method.getReturnType();
}
this.returnsVoid = void.class.equals(this.returnType);
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
this.returnsCursor = Cursor.class.equals(this.returnType);
this.returnsOptional = Optional.class.equals(this.returnType);
this.mapKey = getMapKey(method);
this.returnsMap = this.mapKey != null;
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
致此获取mapper代理对象结束,注意sqlsession每获取一次mapper都会重新生成一个代理对象。
注:最终执行都是通过sqlSession进行crud操作,前面这一些操作仅仅是为了对代理mapper,解析出mapper对应方法对应的sqlsession对应的那个方法去执行,在调用mapper方法时调用sqlsession对应的方法,对结果进行封装返回。
mybatis执行查询是以sqlsession进行,用完之后需要重新构建,之所以使用sqlsession是为了更简单的处理并发,和降低代码编写难度,复核会话的定义。
spring在整合mybatis,写了一个sqlsessionTemplate,实现了sqlsession接口;通过对mapper的代理,拦截对应的方法,创建Mybatis的sqlsession,委托调用创建的Mybatis的sqlsession完成crud,将事物与mybatis剥离,自己进行管理;通过FactoryBean设置构造函数参数实例化MapperFactoryBean通getObject获取sqlSessionTemplate完成整合,后面做详细介绍。
可以参考MapperFactoryBean和SQLSessionTemplate类以及ClassPathMapperScanner.processBeanDefinitions方法
四.执行查询阶段
注:只做查询解析
4.1通过sqlsession查询结果
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// 通过statementId该Id为名称空间加上方法名 获得 MappedStatement 对象
MappedStatement ms = configuration.getMappedStatement(statement);
// 查询
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
4.2委托Executor执行查询
这里对BaseExecutor做解析
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//根据传入的参数动态获得SQL语句,最后返回用BoundSql对象表示
BoundSql boundSql = ms.getBoundSql(parameter);
//为本次查询创建缓存的Key
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
// 查询
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
ms.getBoundSql(parameter)解析
public BoundSql getBoundSql(Object parameterObject) {
// 获得 BoundSql 对象 sqlsource在构建mapperstatement构建,用于对sql解析
// 该SqlSource实现类有 DynamicSqlSource动态sql解析
// ProviderSqlSource@ProviderXXX 注解的 SqlSource 实现类
// RawSqlSource 通过委托该类获取具体的SQLSource(DynamicSqlSource,StaticSqlSource
// , ProviderSqlSource)
// StaticSqlSource 静态sql解析
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}
// check for nested result maps in parameter mappings (issue #30)
// 判断传入的参数中,是否有内嵌的结果 ResultMap 。如果有,则修改 hasNestedResultMaps 为 true
// 存储过程相关,暂时无视
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
return boundSql;
}
执行查询
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
// 已经关闭,则抛出 ExecutorException 异常
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 清空本地缓存,如果 queryStack 为零,并且要求清空本地缓存。
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
// 用于记录调用链是否完成,完成后执行懒加载,用于解决循环依赖问题
queryStack++;
// 从一级缓存中,获取查询结果
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
// 获取到,则进行处理
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//查询数据库,并对查询结果解析
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
// 执行延迟加载,从一级缓存中获取结果并设置到属性中,此处为解决循环依赖最后步骤即设置相互依赖的对象的属性值
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// 清空懒加载
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// 清除缓存
clearLocalCache();
}
}
return list;
}
queryFromDatabase解析
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
// 在一级缓存中,添加占位符用于处理延迟加载,DeferredLoad#canLoad()在结果集处理中处理嵌
// 套子查询,出现循环依赖时,存入DeferredLoad;待所有查询完成后通过
// DeferredLoad#canLoad()从缓存中获取结果设置到属性中
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
// 执行读操作
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
// 移除占位符
localCache.removeObject(key);
}
// 添加到缓存中
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
进入doQuery方法
在解读该方法时先对执行器Executor进行解读
该类的实现类有4个,定义了Executor接口; mybatis为了复用公用方法使用了模板设计模式,在BaseExecutor中实现公用方法后定义了需要需要子类完成不同功能的方法(如下图所示)
在baseExecutor中调用抽象方法,子类实现baseExecutor抽象方法,
完成复用statement的实现类
完成批量操作实现类
完成简单操作实现类
下面对CacheExecutor二级缓存做详细解读:
在CacheExecutor中实现了Executor接口通过委托BaseExecutor的实现类执行crud,将执行结果存入Cache,或在执行前重缓存获取数据,在存入缓存前必须在事务提交后通过缓存事务类提交缓存事务,存入缓存,中途失败则不存入缓存,一但出现修改则清空事务缓存中的数据,设置MappedStatement.flushCacheRequired=true(在BaseExecutor.query中清空缓存代码如下)
注意:只有提交事务后二级缓存才会存入查询的数据,如果在分布条件下不建议使用二级缓存会出现严重的问题,例如A服务查询了一条数据存入缓存(自己实现的缓存,存入redis)中后,A服务有修改了该条数据,清空事务缓存,编辑cache失效;但此时A服务并未去对该名称空间下的数据做查询,这样缓存中的数据任然有效,此时B服务对该条数据做查询,就会导致直接从二级缓存中获取数据,导致查询到失效数据。
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } // 清空本地缓存,如果 queryStack 为零,并且要求清空本地缓存。 if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } }
,只提交事务是才会提交事务缓存中的数据到cache中;
下面我们以SimpleExecutor 为例对doQuery方法做解读
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
// 创建StatementHandler对象(该对象用于创建和设置查询参数), wrapper为自己
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 创建jdbc中的statement对象,设置sql参数
stmt = prepareStatement(handler, ms.getStatementLog());
// 执行 StatementHandler ,进行读操作,该statement已经准备完毕直接执行查询即可
return handler.query(stmt, resultHandler);
} finally {
// 关闭 StatementHandler 对象
closeStatement(stmt);
}
}
下面对configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql)进行解读
该方法主要用于创建RoutingStatementHandler,在该类构造方法中通过MappedStatement.getStatementType构建不同的StatementHandler后将statementHandler作为参数应用插件
// 创建 StatementHandler 对象 public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { // 创建 RoutingStatementHandler 对象 StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); // 应用插件 statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; }
下面对StatementHandler做接读
该类的主要作用是用于创建或处理java.sql.Statement -> SimpleStatementHandler、java.sql.PreparedStatement -> PreparedStatementHandler、java.sql.CallableStatement -> CallableStatementHandler
设置参数等,该类的实现方式与Executor类似,抽象StatementHandler接口后再BaseStatementHandler中实现可复用的方法,调用子类实现的抽象方法;委托到具体的实现类是通过RoutingStatementHandler该类的构造方法
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 根据不同的类型,创建对应的 StatementHandler 实现类
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
适配具体的实现类,然后委托实现类完成statement的创建复用参数设置,结果集处理。
下面对BaseExecutor的构造方法做解读
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
if (boundSql == null) {
generateKeys(parameterObject);
// 创建 BoundSql 对象
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
// 创建 ParameterHandler 对象,此方法用于应用ParameterHandler插件
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
// 创建 ResultSetHandler 对象,此方法用于应用ResultSetHandler插件
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
致此完成了statementHandler的创建完成,statement
下面对handler.query(stmt, resultHandler)做解析
我们以常用sql预编译PreparedStatementHandler做解析,传入该方法的statement已经是处理完毕,直接执行查询的处理代码如下
// 初始化 StatementHandler 对象
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 获得 Connection 对象
Connection connection = getConnection(statementLog);
// 创建 Statement 或 PrepareStatement 对象
stmt = handler.prepare(connection, transaction.getTimeout());
// 设置 SQL 上的参数,该handler为RoutingStatementHandler
handler.parameterize(stmt);
return stmt;
}
执行查询
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 执行查询
ps.execute();
// 处理结果集
return resultSetHandler.handleResultSets(ps);
}
4.3 普通结果集映射
resultSetHandler为BaseExecutor构造方法内 configuration.newResultSetHandler创建的DefaultResultSetHandler
进入handleResultSets方法
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
//忽略
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
// 获得首个 ResultSet 对象,封装成 ResultSetWrapper对象用于结果集的获取可以看做一个
// 工具类
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 忽略
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount); // 校验
while (rsw != null && resultMapCount > resultSetCount) {
// 获得 ResultMap 对象
ResultMap resultMap = resultMaps.get(resultSetCount);
// 处理 ResultSet
handleResultSet(rsw, resultMap, multipleResults, null);
// 获得下一个 ResultSet 对象,并封装成 ResultSetWrapper 对象
rsw = getNextResultSet(stmt);
// 清理
cleanUpAfterHandlingResultSet();
// resultSetCount ++
resultSetCount++;
}
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
return collapseSingleResultList(multipleResults);
}
下面对handleResultSet做解读
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
try {
if (parentMapping != null) {
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
} else {
if (resultHandler == null) {
// 创建 DefaultResultHandler 对象
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
// 处理 ResultSet 返回的每一行 Row
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
multipleResults.add(defaultResultHandler.getResultList());
} else {
// 处理 ResultSet 返回的每一行 Row
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// 关闭ResultSet
closeResultSet(rsw.getResultSet());
}
}
下面对handleRowValues做解读
// 处理 ResultSet的每一行数据
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
// 处理嵌套查询
if (resultMap.hasNestedResultMaps()) {
// 校验不要使用 RowBounds
ensureNoRowBounds();
// 校验resultHandler,安全检测开启的情况下校验结果集是否有序,防止嵌套查询导致的
// 内存溢出,如果无序的话在自定义的ResultHandler中就可能存在对前面结果集的引用,
// 一直将结果集保存导致内存中导致内存溢出
// 方便溢出
checkResultHandler();
// 处理嵌套映射的结果
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
// 处理简单映射
} else {
// 处理简单映射结果
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
下面对handleRowValuesForSimpleResultMap做解读
// 处理简单映射
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
// 获得ResultSet
ResultSet resultSet = rsw.getResultSet();
//跳到rowBounds指定的开始位置
skipRows(resultSet, rowBounds);
// 循环处理每一行row
while (shouldProcessMoreRows(resultContext, rowBounds) // 判断是否继续处理ResultSet
&& !resultSet.isClosed() // ResultSet是否关闭
&& resultSet.next()) { // ResultSet是否存在下一条
// 根据该行记录以及 ResultMap.discriminator获取对应的ResultMap对象
// 该对象用于处理jdbc与实体属性的映射
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
// 通过ResultMap对ResultSet与结果对象做映射,处理懒加载,内部对象映射等
Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
// 将映射创建的结果对象添加到ResultHandler中
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
下面对resolveDiscriminatedResultMap进行解读
public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {
// 记录处理过Discriminator对应的ResultMap的编号
Set<String> pastDiscriminators = new HashSet<>();
// 在resultMap中存在Discriminator对象,则通过其获取ResultMap对象,
// 用于处理一个结果对应多个实现类,根据结果的不同选择不同的实现类
// 例如结果需要映射到A对象,A对象里面有个实现B接口的对象,B对象的实现类有
// d,g,k 根据A对象id对3求余确定使用对应的对象
Discriminator discriminator = resultMap.getDiscriminator();
while (discriminator != null) { // 因为 Discriminator 可以嵌套 Discriminator ,所以是一个递归的过程
// 获得Discriminator字段,在ResultSet中的值
final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
// 从 Discriminator 获取该值对应的ResultMap的id
final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
// 存在,则使用该ResultMap对象继续遍历
if (configuration.hasResultMap(discriminatedMapId)) {
// 获得该 ResultMap 对象
resultMap = configuration.getResultMap(discriminatedMapId);
// 出现重复结束循环
Discriminator lastDiscriminator = discriminator;
discriminator = resultMap.getDiscriminator();
if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
break;
}
// 如果不存在,直接结束循环
} else {
break;
}
}
return resultMap;
}
接下来对getRowValue做解读
该方法主要通过resultMap对resultSet与结果对象做映射
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
// 用于懒加载,将懒加载的查询封装成该对象通过load方法查询结果并通过
// metaObject设置到原对象的属性中
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
// 创建结果对象,若该结果集存在懒加载则对对象的get方法做代理
// 在调用get方法时通过lazyLoader.loadResult 查询结果并形成闭环
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
// 创建MetaObject对象用于给映射对象设置属性值
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
// 是否开启自动映射功能,若开启则对未确定的列进行自动映射
if (shouldApplyAutomaticMappings(resultMap, false)) {
// 自动映射
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
// 映射ResultMap中propertyResultMappings相关列
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
// 改行映射已完成
foundValues = lazyLoader.size() > 0 || foundValues;
// 如果映射失败则返回null
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
下面对applyPropertyMappings方法做解读
// 映射结果集
private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
// 获取字段名数组
final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
boolean foundValues = false;
// 遍历ResultMapping并做值映射
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
for (ResultMapping propertyMapping : propertyMappings) {
// 获得字段名
String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
if (propertyMapping.getNestedResultMapId() != null) {
// the user added a column attribute to a nested result map, ignore it
// 如果含有嵌套结果集映射,忽略该字段,在applyNestedResultMappings方法处理嵌
// 套映射
column = null;
}
if (propertyMapping.isCompositeResult() // 组合
|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) // 属于 mappedColumnNames
|| propertyMapping.getResultSet() != null) { // 存储过程
// 获得指定字段的值
Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
// issue #541 make property optional
final String property = propertyMapping.getProperty();
if (property == null) {
continue;
} else if (value == DEFERED) {
foundValues = true;
continue;
}
// 标记获取到任一属性
if (value != null) {
foundValues = true;
}
// 设置属性值
if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {
metaObject.setValue(property, value);
}
}
}
return foundValues;
}
下面对getPropertyMappingValue方法做解读,该方法完成获取属性值以及嵌套查询
// 获取字段的值
private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
if (propertyMapping.getNestedQueryId() != null) {//嵌套查询直接调用getNestedQueryMappingValue方法进行查询
return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
} else if (propertyMapping.getResultSet() != null) {
addPendingChildRelation(rs, metaResultObject, propertyMapping); // TODO is that OK?
return DEFERED;
} else { // 普通的直接返回指定字段的值
final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
return typeHandler.getResult(rs, column);
}
}
下面对嵌套查询方法getNestedQueryMappingValue做解读
// 嵌套查询方法
private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
// 获得子查询查询的
final String nestedQueryId = propertyMapping.getNestedQueryId();
// 获得属性名
final String property = propertyMapping.getProperty();
// 获得嵌套查询MappedStatement
final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
// 获得嵌套查询参数类型
final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
// 获得嵌套查询的参数
final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping, nestedQueryParameterType, columnPrefix);
Object value = null;
if (nestedQueryParameterObject != null) {
// 获取BoundSql
final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
// 获得取 CacheKey
final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT, nestedBoundSql);
final Class<?> targetType = propertyMapping.getJavaType();
// 检查缓存是否以存在,前面在进入查询是设置过占位符到缓存中,此处用于解决循环依赖
if (executor.isCached(nestedQuery, key)) {
// 若果存在创建 DeferredLoad 对象,通过该对象从缓存中加载并设置属性值
executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
// 返回以定义标记
value = DEFERED;
} else {// 缓存中不存在
// 创建 ResultLoader 对象 用于加载结果
final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery, nestedQueryParameterObject, targetType, key, nestedBoundSql);
// 处理延时加载
if (propertyMapping.isLazy()) {
// 该属性配置了延迟加载,将其添加到ResultLoader.loaderMap中,通过代理过的get方法调用resultLoader.loadResult方法查询结果并返回
// get代理方法在创建结果对象时做的代理
lazyLoader.addLoader(property, metaResultObject, resultLoader);
// 返回已定义
value = DEFERED;
} else {// 直接加载结果
value = resultLoader.loadResult();
}
}
}
return value;
}
下面对 resultLoader.loadResult()方法做解读
/**
* 查询结果并获取结果
*
* @return 结果
*/
public Object loadResult() throws SQLException {
// 执行查询
List<Object> list = selectList();
// 获取结果
resultObject = resultExtractor.extractObjectFromList(list, targetType);
// 返回结果
return resultObject;
}
查询结果解析结果结束返回
4.4 mybatis嵌套结果集映射
大概逻辑为:
假设结果集映射含有A,B,C三个对象其中B为A的属性对象,关联关系为A的id,C为B的属性对象关联关系为B的id;循环遍历查询出来的结果集,我们以遍历过程中的一行结果记录为例,先为A对象创建rowKey(xml文件中resultMap 的<id>属性作为标识创建,有几个id就用几个id作为区分多行数数据中应该属于同一对象),从nestedResultObjects缓存中获取是否存在相同的对象数据,如果不存在,则对A对象的普通属性做映射,映射后将A对象以rowKey作为Key,A对象作为Value存入nestedResultObjects中, 如果nestedResultObjects存在则对A对象中的子对象B做映射,在映射B对象的过程中同样创建rowkey后创建组合键combinedKey,然后以combinedKey作为key从nestedResultObjects或B对象,以同样的逻辑直到所有嵌套结果集全都映射完成
下面为对核心代码的注释
while (shouldProcessMoreRows(resultContext, rowBounds)
&& !resultSet.isClosed()
&& resultSet.next()) {
// 处理鉴别器,获取ResultMap
final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
//创建rowKey
final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
Object partialObject = nestedResultObjects.get(rowKey);
//结果集有序的情况下
if (mappedStatement.isResultOrdered()) {
if (partialObject == null && rowValue != null) {
nestedResultObjects.clear();
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
} else {
//获取获取映射结果集 partialObject作为判断对象普通属性是否已映射
//不为空已映射,为空未映射
rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
if (partialObject == null) {
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
}
下面对getRowValue方法做注释
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException {
final String resultMapId = resultMap.getId();
Object rowValue = partialObject;
//从缓存中获取到,则认为改行父对象普通属性已解析,只需解析内嵌对象
if (rowValue != null) {
final MetaObject metaObject = configuration.newMetaObject(rowValue);
//将父对象存入ancestorObjects中防止循环解析问题
putAncestor(rowValue, resultMapId);
//映射内嵌结果对象
applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
//将父对象重ancestorObjects中移除
ancestorObjects.remove(resultMapId);
} else
//从缓存中未获取到,则认为即要映射普通属性也要映射嵌套对象
{
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
//创建对象,若存在懒加载对get方法做代理
rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if (shouldApplyAutomaticMappings(resultMap, true)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
//为普通属性赋值
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
//将父对象存入ancestorObjects中防止循环解析问题
putAncestor(rowValue, resultMapId);
//映射嵌套对象
foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
//将父对象重ancestorObjects中移除
ancestorObjects.remove(resultMapId);
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
if (combinedKey != CacheKey.NULL_CACHE_KEY) {
nestedResultObjects.put(combinedKey, rowValue);
}
}
return rowValue;
}
下面对applyNestedResultMappings方法作注释
private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String parentPrefix, CacheKey parentRowKey, boolean newObject) {
boolean foundValues = false;
for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
final String nestedResultMapId = resultMapping.getNestedResultMapId();
// nestedResultMapId不为空则为内嵌对象
if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
try {
//获取字段前缀
final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
// 获取ResultMap
final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId, columnPrefix);
if (resultMapping.getColumnPrefix() == null) {
// try to fill circular reference only when columnPrefix
// is not specified for the nested result map (issue #215)
// 仅在 columnPrefix 为空时,尝试填充循环引用,用于嵌套结果映射
// 前面有存入过
Object ancestorObject = ancestorObjects.get(nestedResultMapId);
if (ancestorObject != null) {
// 如是出现循环依赖,直接使用ancestorObject
if (newObject) {
linkObjects(metaObject, resultMapping, ancestorObject); // issue #385
}
//不进行后续步骤
continue;
}
}
// 创建内嵌对象的CacheKey
final CacheKey rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
//创建组合Key
final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
// 从nestedResultObjects中获取
Object rowValue = nestedResultObjects.get(combinedKey);
boolean knownValue = rowValue != null;
// 如果当前对象是集合嵌套,则对集合对象进行初始化
instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
// 不为空的对象属性不能为空
if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw)) {
// 处理嵌套对象的属性值,再次进入getRowValue,同样的逻辑
rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix, rowValue);
// 如果嵌套对象非空
if (rowValue != null && !knownValue) {
linkObjects(metaObject, resultMapping, rowValue);
foundValues = true;
}
}
} catch (SQLException e) {
throw new ExecutorException("Error getting nested result map values for '" + resultMapping.getProperty() + "'. Cause: " + e, e);
}
}
}
return foundValues;
}