/*
	ResultSets = [ // 《批量结果集列表》,要数据库支持
		ResultSet : [ // 记录列表
			Result {id:1, name:"name_1",pwd:"pwd_1"}, // 一行记录
			Result {id:2, name:"name_2",pwd:"pwd_2"},
			Result {id:3, name:"name_3",pwd:"pwd_3"}
		],
		ResultSet :[
			Result {id:1, name:"name_1",pwd:"pwd_1"},
			Result {id:2, name:"name_2",pwd:"pwd_2"},
			Result {id:3, name:"name_3",pwd:"pwd_3"}
		]
	]
 */
// 0、获取文件输入流
InputStream inputStream = Resources.getResourceAsStream("foo-config.xml");

// org.apache.ibatis.scripting.defaults.RawLanguageDriver

/*
	1、解析 xml 文件,设置配置到 Configuration 对象
		解析mapper
			1、解析《xml类型》的mapper
  			2、解析《注解类型》的mapper
  				if(类的类型是接口类型)
  				{
  					1、尝试加载  "com/test/bean/XxxMapper.xml"文件,如果存在就进行解析
  					2、解析类上的 @CacheNamespace 注解,创建Cache对象,并设置cache到currentCache
  					3、解析类上的 @CacheNamespaceRef 注解,获取Cache对象,并设置cache到currentCache
  					4、迭代方法
						for (Method method : methods)
						{
							1、解析方法的参数类型 ParamMap、自定义类 FooBean、简单类型 Integer
							2、解析方法上的 @Lang 注解,如果没有配置获取全局默认的值。如 org.apache.ibatis.scripting.defaults.RawLanguageDriver,org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
							3、创建SqlSource对象,解析方法上的《@Select..》和 《@SelectProvider..》的注解;两种类型不能同时存在
								1、@Select、@Insert、@Update、@Delete 注解
									1、获取注解的值(多值用 "," 连接)
									2、用 StringBuilder 拼接注解值
									3、创建SqlSource对象 --- 使用 @Lang 配置的 Driver
										如 RawLanguageDriver
											org.apache.ibatis.scripting.defaults.RawLanguageDriver.createSqlSource(configuration对象,sql字符串,参数类型)
											{
												1、SqlSource source = XMLLanguageDriver.createSqlSource(configuration, script, parameterType);
												{
													// ...
												}

												2、检查 source 是否是 RawSqlSource 的实例,否则抛异常
											}

										如 XMLLanguageDriver
											org.apache.ibatis.scripting.defaults.XMLLanguageDriver.createSqlSource(configuration对象,sql字符串,参数类型)
											{
												1、以<script>开头
													。。。解析xml节点 。。。

												2、不以<script>开头
													1、用配置的变量 configuration.getVariables() 替换第一层 ${...}
													2、如果还存在${...} ,那么创建DynamicSqlSource对象并返回

													3、如果不存在${...} ,那么创建RawSqlSource对象并返回
														1、解析 #{...},用 "?" 替换,
														2、注册 占位符 到 parameterMappings,执行的时候走bindParams
											}

								2、@SelectProvider、@InsertProvider、@UpdateProvider、@DeleteProvider 注解
									1、创建 ProviderSqlSource 对象

							4、解析方法上的 @Options 注解
							{
								0、生成语句ID final String mappedStatementId = type.getName() + "." + method.getName();
								1、获取命令类型 SqlCommandType sqlCommandType = getSqlCommandType(method)
								2、获取键生成器
									if(INSERT、UPDATE类型的命令)
									{
										if(获取@SelectKey注解配置)
										{
											keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver);
											{
												1、获取@SelectKey配置的 返回值类型、语句类型、语句、键的名称
												2、生成语句ID type.getName() + "." + method.getName() + "!selectKey"
												3、字段的关系
													// 获取keyColumn的值,设置到目标sql的keyProperty属性中
													String keyProperty = selectKeyAnnotation.keyProperty(); // 目标sql的属性名
													String keyColumn = selectKeyAnnotation.keyColumn(); // 获取属性值的列名,数量与keyProperty相同
												4、创建 MappedStatement,并添加到 configuration
													configuration.addMappedStatement(statement);
												5、添加key生成器
													SelectKeyGenerator answer = new SelectKeyGenerator(keyStatement, executeBefore);
													configuration.addKeyGenerator(id, answer);
											}
  											keyProperty = selectKey.keyProperty();
										}
										else if (没有配置 @Options)
										{
											keyGenerator = configuration.isUseGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
										}
										else (有配置 @Options)
										{
											keyGenerator = options.useGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
											keyProperty = options.keyProperty();
											keyColumn = options.keyColumn();
										}
									}
									else
									{
										keyGenerator = new NoKeyGenerator();
									}

								3、有配置 @Options
									1、获取缓存配置
									2、获取批量获取数量配置
									3、获取超时配置
									4、语句类型 StatementType.PREPARED
									5、返回集类型 ResultSetType.FORWARD_ONLY
							}

							5、处理返回值类型
							{
								if(方法上有 @ResultMap 注解)
								{
									// @ResultMap(value={"resultMap1","resultMap2"})
									resultMapId = sb.toString();
								}
								else(没有注解 @ResultMap 并且是 查询)
								{
									1、获取返回值类型
									2、解析方法上的 @ConstructorArgs 注解
									3、解析方法上的 @Results 注解
									4、解析方法上的 @TypeDiscriminator 注解
									5、生成 resultMapId
										if(解析方法上有 @Results 注解,并设置了id)
										{
											return type.getName() + "." + results.id();
										}
										else
										{
											if(方法有参数)
											{
												suffix = "-" + "参数名用-拼接"
											}
											else
											{
												suffix = "-void"
											}
											return type.getName() + "." + method.getName() + suffix;
										}

									6、应用
										1、迭代Arg注解,创建ResultMapping,添加到resultMappings
										2、迭代Result注解,创建ResultMapping,添加到resultMappings
										3、解析TypeDiscriminator注解,创建ResultMapping,创建Discriminator对象包装
										4、添加到configuration
											// resultMapId == "cn.java.mapper.FooMapper.method1-param0-param1"
											// !!! 创建对象ResultMap,添加到configuration
											assistant.addResultMap(resultMapId, returnType, null, disc, resultMappings, null);
										5、迭代@TypeDiscriminator注解的@case属性
											for (Case c : discriminator.cases())
											{
												// resultMapId == "cn.java.mapper.FooMapper.method1-param0-param1"
												String caseResultMapId = resultMapId + "-" + c.value();
												List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
												applyConstructorArgs(c.constructArgs(), resultType, resultMappings);
												applyResults(c.results(), resultType, resultMappings);

												// caseResultMapId === "cn.java.mapper.FooMapper.method1-param0-param1-" + c.value()
												// !!! 创建对象ResultMap,添加到configuration
												assistant.addResultMap(caseResultMapId, c.type(), resultMapId, null, resultMappings, null);
											}

								}
							}
						}
					5、构建 MappedStatement 对象
						mappedStatement
						{
							....
							sqlSource : sqlSource,
							parameterMap : ...,
							resultMaps : ...,
							...
						}
						。。。
  				}

	2、创建 DefaultSqlSessionFactory 对象
 */
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);


/*
	1、创建《事务对象》JdbcTransaction
		tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

	2、创建《执行器》
		Executor executor = configuration.newExecutor(tx, execType)
		{
			1、创建执行器
				executor = new SimpleExecutor(this, transaction);

			2、用 CachingExecutor 代理 SimpleExecutor ------- 用于缓存控制
				if (cacheEnabled) { // 允许缓存
				  executor = new CachingExecutor(executor);
				}

			3、安装插件
				executor = (Executor) interceptorChain.pluginAll(executor); // 安装《拦截器》,返回代理对象 ---- 用于执行executor的时候拦截
				{
					for (Interceptor interceptor : interceptors) {
					  target = interceptor.plugin(target); // 返回被代理的对象
					  {
						  return Plugin.wrap(target, this);
						  {
							  1、解析拦截器类上的 @Intercepts、@Signature 注解,识别要拦截的目标方法,创建特征map
							  2、创建代理对象返回
						  }
					  }
					}
					return target;
				}
		}

	3、创建 DefaultSqlSession
	{
		return new DefaultSqlSession(configuration, executor, autoCommit);
	}
 */
// 自动提交的方式打开 DefaultSqlSession,会创建一个Transaction对象跟随
SqlSession sqlSession = sqlSessionFactory.openSession(true);  // 打开连接(会从“数据源”中获取一个,如果没有会“创建一个”)

{
	List<Foo> fooList = sqlSession.selectList("cn.java.demo.mybatis.mapper.FooTwoNonInterfaceHaveXmlNonAnnotationMapper.selectListReturnListInXml", 1);
	for (Iterator iterator = fooList.iterator(); iterator.hasNext(); ) {
		Foo foo = (Foo) iterator.next();
		System.out.println(foo);
	/*
		1、获取 MappedStatement
			MappedStatement ms = configuration.getMappedStatement(statement);

	   	2、执行
	   		return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); // 执行目标方法
	   		{
	   			1、递归调用拦截器链条
					for(拦截器列表) --------- 应用拦截器 --- 要执行executor的时候拦截
					{
						// ....
					}

	   			2、执行目标 executor
	   				1、执行缓存 CachingExecutor
	   					Cache cache = ms.getCache(); // 由类上的 @CacheNamespace 或者 @CacheNamespaceRef 控制
						if (cache != null) { // 如果有配置外部缓存依赖,如 Redis
							flushCacheIfRequired(ms); // 刷新外部缓存,如Redis
							if (ms.isUseCache() && resultHandler == null) { // 使用外部缓存,如Redis,方法上的注解 @Options(useCache=true)
								ensureNoOutParams(ms, parameterObject, boundSql);
								@SuppressWarnings("unchecked")
								List<E> list = (List<E>) tcm.getObject(cache, key); // 从外部缓存获取数据,如Redis
								if (list == null) {
									list = delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); // ------- 执行目标 Executor
									tcm.putObject(cache, key, list); // issue #578 and #116 数据放入外部缓存,如Redis
								}
								return list;
							}
						}
						// delegate === org.apache.ibatis.executor.SimpleExecutor
						return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); // ------- 执行目标 Executor

	   				2、执行目标 Executor
						// 当配置执行器类型为:ExecutorType.BATCH
						org.apache.ibatis.executor.BatchExecutor.query()
						{

						}

						// 当配置执行器类型为:ExecutorType.REUSE
						org.apache.ibatis.executor.ReuseExecutor.query()
						{

						}

						// 否则
						org.apache.ibatis.executor.SimpleExecutor.query()
						{
							1、解析SQL,替换#{}为占位符 ?、解析绑定参数
							{
								BoundSql boundSql = ms.getBoundSql(parameter);
								{
									// parameterObject 实际调用时传递进来的参数
									// sqlSource === org.apache.ibatis.scripting.defaults.RawSqlSource !!! -----  @Select("select * from table1 where field1 = #{field1_property} AND field2 = #{field2_property,:JdbcType.VARCHAR,javaType=java.lang.String,mode=ParameterMode.IN,numericScale=2,resultMap=resultMapId,typeHandler=typeHandlerAlias,jdbcTypeName=jdbcTypeName}")
									// sqlSource === org.apache.ibatis.scripting.xmltags.DynamicSqlSource !!! -----  @Select("select * from table1 where field1 = ${parampre\\${param_middle\\}paramafter}")
									BoundSql boundSql = sqlSource.getBoundSql(parameterObject); // 构建sql
									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)
									for (ParameterMapping pm : boundSql.getParameterMappings()) { // 绑定参数
										String rmId = pm.getResultMapId(); // 结果映射id
										if (rmId != null) {
											ResultMap rm = configuration.getResultMap(rmId);
											if (rm != null) {
												hasNestedResultMaps |= rm.hasNestedResultMaps();
											}
										}
									}

									return boundSql;
								}
							}

							2、创建缓存key
								CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);

							3、执行查询
								return query(ms, parameter, rowBounds, resultHandler, key, boundSql); // 查询

								1、如果配置缓存、清除本地缓存
									if (queryStack == 0 && ms.isFlushCacheRequired()) { // 需要缓存
									   clearLocalCache(); // 清除本地缓存
									   {
											if (!closed) {
											  localCache.clear();
											  localOutputParameterCache.clear();
											}
									   }
									}

								2、获取数据
									list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; // 尝试从本地缓存获取
									if (list != null) { // 本地缓存存在数据
										handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); // 从本地缓存获取数据,设置到 parameter
									} else { // 从数据库获取
										list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); // 从数据库获取!!!
										{
											1、查询数据
												list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
												{
													1、获取配置
														Configuration configuration = ms.getConfiguration();

													2、创建语句处理器
														// handler == org.apache.ibatis.executor.statement.RoutingStatementHandler
														StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
														{
															1、创建RoutingStatementHandler对象
																// parameterObject 实际调用时传递进来的参数
																StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
																{
																	switch (ms.getStatementType()) {
																		case STATEMENT: // delegate(ms.getStatementType()=="STATEMENT")
																			delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
																			break;
																		case PREPARED: // delegate(ms.getStatementType()=="PREPARED")
																			//	!!! 创建 PreparedStatementHandler 对象
																			delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
																			{
																				this.configuration = mappedStatement.getConfiguration();
																				this.executor = executor;
																				this.mappedStatement = mappedStatement;
																				this.rowBounds = rowBounds; // RowBounds.DEFAULT 对翻页的限制

																				this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
																				this.objectFactory = configuration.getObjectFactory();

																				// 生成sql语句
																				if (boundSql == null) {
																					generateKeys(parameterObject);
																					boundSql = mappedStatement.getBoundSql(parameterObject); // !!!
																				}

																				this.boundSql = boundSql;

																				// 创建参数处理器
																				this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
																				{
																					1、创建 ParameterHandler 对象
																						// org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
																						ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
																					2、安装插件 --- 用于赋值参数的时候拦截
																						parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler); // org.apache.ibatis.scripting.defaults.DefaultParameterHandler
																				}

																				// 创建结果集处理器
																				this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
																				{
																					1、创建 ResultSetHandler r对象
																						ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
																					2、安装插件 --- 用于处理结果的时候拦截
																						resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
																				}
																			}
																			break;
																		case CALLABLE: // delegate(ms.getStatementType()=="CALLABLE")
																			delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
																			break;
																		default:
																			throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
																	}
																}
															2、安装插件
																statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
														}

													3、预处理语句
														stmt = prepareStatement(handler, ms.getStatementLog());
														{
															Statement stmt;
															Connection connection = getConnection(statementLog);
															{
																1、加载数据库驱动、创建连接、设置事务自动提交和隔离级别
																2、用PooledConnection包装连接
																3、创建PooledConnection的代理对象并返回
															}


															stmt = handler.prepare(connection, transaction.getTimeout()); // handler == org.apache.ibatis.executor.statement.RoutingStatementHandler
															{
																1、递归调用拦截器链条
																	for(拦截器列表) --------- 应用拦截器 --- 要执行sql的时候拦截 -- 拦截 StatementHandler
																	{
																		// ....
																	}

																2、调用目标方法
																	org.apache.ibatis.executor.statement.PreparedStatementHandler.prepare(...)
																	{
																		1、初始化语句
																			statement = instantiateStatement(connection);
																			{
																				// 1、获取sql
																				String sql = boundSql.getSql();

																				// 2、预编译sql
																				if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
																					String[] keyColumnNames = mappedStatement.getKeyColumns();
																					if (keyColumnNames == null) {
																						return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); // 默认:插入后返回主键
																					} else {
																						return connection.prepareStatement(sql, keyColumnNames); // keyColumnNames:插入后必须返回的字段
																					}
																				} else if (mappedStatement.getResultSetType() != null) {
																					return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
																				} else { // 预置语句
																					return connection.prepareStatement(sql); // sql = "select * from table1 where field1 = ?"
																				}
																			}

																		2、设置超时时间
																			setStatementTimeout(statement, transactionTimeout);
																			{
																				Integer queryTimeout = null;
																				if (mappedStatement.getTimeout() != null) {
																					queryTimeout = mappedStatement.getTimeout(); // 注解上配置的超时时间
																				} else if (configuration.getDefaultStatementTimeout() != null) {
																					queryTimeout = configuration.getDefaultStatementTimeout(); // 默认超时时间
																				}
																				if (queryTimeout != null) {
																					stmt.setQueryTimeout(queryTimeout);
																				}
																				StatementUtil.applyTransactionTimeout(stmt, queryTimeout, transactionTimeout);
																			}

																		3、设置获取数量
																			setFetchSize(statement);
																			{
																				Integer fetchSize = mappedStatement.getFetchSize(); // 注解上配置的获取数量
																				if (fetchSize != null) {
																					stmt.setFetchSize(fetchSize);
																					return;
																				}
																				Integer defaultFetchSize = configuration.getDefaultFetchSize(); // 默认获取数量
																				if (defaultFetchSize != null) {
																					stmt.setFetchSize(defaultFetchSize);
																				}
																			}
																			return statement;
																	}
															}



															2、绑定参数
															handler.parameterize(stmt); // 赋值参数
															{
																0、递归调用拦截器链条
																	for(拦截器列表) --------- 应用拦截器 --- 要执行sql的时候拦截 -- 拦截 StatementHandler
																	{
																		// ....
																	}

																1、拦截器执行完成,执行目标 DefaultParameterHandler
																	org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(PreparedStatement stmt)
																	{
																		0、递归调用拦截器链条
																			for(拦截器列表) --------- 应用拦截器(参数绑定的时候拦截) -- 拦截 ParameterHandler
																			{
																				// ....
																			}

																		1、执行目标代码
																			for (int i = 0; i < parameterMappings.size(); i++)
																			{
																				ParameterMapping parameterMapping = parameterMappings.get(i);
																				if (parameterMapping.getMode() != ParameterMode.OUT) {
																					1、获取绑定值
																						String propertyName = parameterMapping.getProperty(); // 属性名 foo.account
																						MetaObject metaObject = configuration.newMetaObject(parameterObject); // 其他类型
																						value = metaObject.getValue(propertyName);

																					2、获取类型转换器
																						TypeHandler typeHandler = parameterMapping.getTypeHandler(); // 属性的类型处理器
																						JdbcType jdbcType = parameterMapping.getJdbcType(); // 数据库的类型 org.apache.ibatis.type.JdbcType.VARCHAR

																					3、转换类型,并设置值
																						typeHandler.setParameter(ps, i + 1, value, jdbcType); // org.apache.ibatis.type.StringTypeHandler
																				}
																			}
																	}
															}
															return stmt;
														}

													3、执行查询
														return handler.<E>query(stmt, resultHandler);
														{
															PreparedStatement ps = (PreparedStatement) statement;
															1、执行语句
																ps.execute(); // 执行SQL语句

															2、处理结果集
																return resultSetHandler.<E>handleResultSets(ps);
																{
																	1、拦截器执行完成,执行目标 DefaultResultSetHandler
																		org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(PreparedStatement ps)
																		{
																			0、递归调用拦截器链条
																				for(拦截器列表) --------- 应用拦截器(处理返回结果的时候拦截) -- 拦截 ResultSetHandler
																				{
																					// ....
																				}

																			1、获取第一个结果集ResultSet,并用ResultSetWrapper包装
																				ResultSetWrapper rsw = getFirstResultSet(stmt);

																			2、获取配置的映射
																				List<ResultMap> resultMaps = mappedStatement.getResultMaps(); // (通过注解 @ResultMap("resultMap1,resultMap2")得到 或者 “解析返回参数并内建” 得到 或者 解析注解@ConstructorArgs、@Results、@TypeDiscriminator)
																				int resultMapCount = resultMaps.size(); // 配置的“结果集定义”的数量
																				validateResultMapsCount(rsw, resultMapCount); // resultMaps数量必须大于0

																			3、填充结果数据
																				while (rsw != null && resultMapCount > resultSetCount) { // “结果集定义”的数量 大于 “数据库返回的结果集”数量(即:数据库的某个结果集有配置映射信息)
																					ResultMap resultMap = resultMaps.get(resultSetCount); // 第N个结果集映射器 org.apache.ibatis.mapping.ResultMap / ResultMap 描述的是某一行数据怎么映射的信息
																					handleResultSet(rsw, resultMap, multipleResults, null); // 处理结果集 --------处理结果集(即:行列表)
																					{
																						if (resultHandler == null) { // 在方法上没有定义 ResultHandler 对象
																							DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
																							handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);// !!! ---------------debug
																							{
																								if (resultMap.hasNestedResultMaps()) { // 有嵌套
																									ensureNoRowBounds();
																									checkResultHandler();
																									handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
																								} else { // !!!
																									handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); // -------------
																									{
																										DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
																										skipRows(rsw.getResultSet(), rowBounds); // 根据rowBounds的配置,跳过N行
																										{
																											if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
																												if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
																													rs.absolute(rowBounds.getOffset());
																												}
																											} else {
																												for (int i = 0; i < rowBounds.getOffset(); i++) {
																													rs.next();
																												}
																											}
																										}
																										while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) { // ------------- 迭代所有行
																											ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null); // org.apache.ibatis.mapping.ResultMap
																											Object rowValue = getRowValue(rsw, discriminatedResultMap); // 获取某行数据 !!!------
																											{
																												1、创建Entity对象
																													Object resultObject = createResultObject(rsw, resultMap, lazyLoader, null); // !!! 创建行或者结果对象 FooOneEntity

																												2、填充数据到Entity对象
																													if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { // 没有类型处理器
																														final MetaObject metaObject = configuration.newMetaObject(resultObject);
																														boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty(); // 有构造函数映射
																														if (shouldApplyAutomaticMappings(resultMap, false)) { // 自动映射
																															foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues; // 应用映射---- metaObject.setValue(mapping.property, value); // 设置值
																														}

																														foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues; // 应用属性值
																														{
																															final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings(); // 属性映射列表
																															for (ResultMapping propertyMapping : propertyMappings) {
																																Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);  // 获取数据库返回的列值
																																metaObject.setValue(property, value); // 设置值
																															}
																															return foundValues;
																														}
																														foundValues = lazyLoader.size() > 0 || foundValues;
																														resultObject = foundValues ? resultObject : null;
																														return resultObject;
																													}
																											}

																											storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); // ...
																											{
																												resultContext.nextResultObject(rowValue);
																												{
																													resultCount++;
																													this.resultObject = resultObject;
																												}

																												((ResultHandler<Object>) resultHandler).handleResult(resultContext);
																												{
																													org.apache.ibatis.executor.result.DefaultResultHandler.handleResult()
																													{
																														list.add(context.getResultObject());
																													}
																												}
																											}
																										} // EDN while
																									}
																								}
																							}
																							multipleResults.add(defaultResultHandler.getResultList(){
																								return list; // 返回列表
																							});
																						} else {
																							handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
																						}
																					}
																					rsw = getNextResultSet(stmt); // 获取下一个结果集
																					cleanUpAfterHandlingResultSet();
																					resultSetCount++;
																				}

																			4、处理父级别的mapping
																				String[] resultSets = mappedStatement.getResultSets(); // !!!!-------  通过注解 @Options(resultSets="resultSets1")得到 ,多结果集的支持
																				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++;
																					}
																				}

																			5、返回结果集合
																				return collapseSingleResultList(multipleResults); // 返回一个结果集
																				{
																					return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
																				}
																		}
																}
														}
												}
											2、数据放入本地缓存
												localCache.putObject(key, list); // 数据本地缓存
										}
									}

								3、清除本地缓存
									if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
										clearLocalCache(); // 清除本地缓存
										{
											if (!closed) {
											  localCache.clear();
											  localOutputParameterCache.clear();
											}
									   }
									}
	   				}
	   		}
	 */
	}
}


sqlSession.close(); // 断开连接(会断开从“数据源”获取的连接,实际上是把连接“放回数据源连接池”中)