Configuration(以下四大组件,皆有configuration创建)
Excutor
CatchingExcutor(二级缓存)(一级缓存已Mapper为级别,以mapper中的namespace为key,存储一个map)
BaseExcutor(将下面三种执行器的一级缓存的功能抽取到此父类中。)(一级缓存已SqlSession为级别,以格式化后的sql语句为key,存储一个map)
SimpleExcutor(简单执行器)
BatchExcutor(批处理)
ReuseExcutor(可重用)
StatementHandler
RouingStatementHandler(路由->由下面三个处理器执行具体的逻辑创建statement)
PreparedStatementHandler(带参数)
CallableStatementHandler(存储过程)
SimpleStatementHandler(简单语句)
ParameterHandler
DefaultParameterHandler(参数设置处理)
ResultSetHandler
DefaultResultSetHandler(结果封装处理)
mybatis-config.xml是怎么解析的?
通过指定文件路径,获取文件流,将文件中的配置信息,封装成Configuration对象.
mapper.xml是怎么解析的?
mybatis-config.xml中有mapper标签,用于指定mapper.xml文件路径。
每个mapper都有自己的namespace命名空间,然后依次解析<cache-ref>、<parameterMap>、<resultMap>、<sql>、<select>\<insert>\<update>\<delete>等标签,根据解析的内容,构建MappedStatement对象,一个mapper.xml对应一个MapperdStatement对象,通过namespace做唯一标识。
MapperdStatement对象中包含id、SqlSource、StatementType、SqlCommandType、入参类型、结果类型、使用缓存等参数
动态标签是怎么解析的?
mapper.xml解析<select>\<insert>\<update>\<delete>等标签时,会创建SqlSource,用于后面创建MapperdStatement对象。
创建SqlSource时,初始化动态sql标签处理器XMLScriptBuilder,XMLScriptBuilder会构建解析动态标签的sqlNode封装到MixedSqlNode的集合中
将带有${}号的SQL信息封装到TextSqlNode
将带有#{}号的SQL信息封装到StaticTextSqlNode
将动态SQL标签中的SQL信息分别封装到不同的SqlNode中
然后使用策略模式,如IfHandler、OtherwiseHandler、ChooseHandler、ForEachHandler等。将不同的标签,通过不同的Handler进行处理,最后得到MixedSqlNode。
入参是怎么赋值的?
Executor查询时,会首先调用getBoundSql()方法,将解析后的SQL语句还有入参绑定到一起,得到一个BoundSql对象,在通过判断二级和一级缓存不存在时,查询数据库时,创建链接、获取statement后,再根据BoundSql对象的数据,给PreparedSateement设置参数。
结果集是怎么映射为对象的?
根据配置的响应类型resultType,通过类加载器得到类的信息,使用类的反射机制,将结果集对应的结果,映射到实体对象中返回。
缓存怎么实现的?
在Executor执行查询时,判断二级缓存是否开启,如果开启并且结果集是不为空,那么取二级缓存返回,否则查询一级缓存。(二级缓存由事务缓存管理器处理TransactionalCacheManager)
首先根据sql和入参生成缓存key,判断一级缓存是否存在该key,如果该缓存key存在则取出,反之取数据库。(一级缓存由mybatis在内存维护一个map对象)
Excutor、StatementHandler、ParameterHandler、ResultSetHandler是什么时候被创建的,被谁创建?
Excutor:sqlSessionFactory.openSession(),通过配置环境信息,先创建事务,在根据事务和执行器类型,创建执行器,如果是开启缓存(默认开启),那么默认使用缓存执行器。(由configuration创建,configuration.newExecutor)
Statement:执行查询时,首先根据statementId获取MapperdStatement,然后判断二级缓存,一级缓存,最后使用执行器,MapperdStatement,BoundSql等参数创建StatementHandler。(由configuration创建,configuration.newStatementHandler)
ParameterHandler:创建StatementHandler时,StatementHandler的基类BaseStatementHandler的构造器中创建了ParameterHandler
ResultSetHandler:创建StatementHandler时,StatementHandler的基类BaseStatementHandler的构造器中创建了ResultSetHandler
Excutor做了那些事?
获取链接,处理事务,用于执行 增|删|改 语句,事务的提交与回滚,以及缓存执行器会查询缓存
StatementHandler做了哪些事?
实例化Statement,设置参数,获取BoundSql,设置查询超时时间,处理修改和查询
ParameterHandler做了哪些事?
给PreparedStatement设置参数。
ResultSetHandler做了哪些事?
处理结果集映射,完成映射返回对象。
负责游标对象处理
负责存储过程的输出参数
缓存什么时候会清除?
二级缓存只有当数据库做了更新操作时会被清空。mapper级别(namespace)
一级缓存当从数据库查询结束后会更新数据。数据库做更新操作时清空。SqlSession级别
SimpleExcutor(简单执行器)、BatchExcutor(批处理)、ReuseExcutor(可重用)有什么区别?
SimpleExcutor:对增删改查生效,为每个语句创建一个statement,语句结束关闭statement
BatchExcutor:对增删改生效,将多条语句,创建多个statementList,一次性访问数据库
ReuseExcutor:建立一个Map<sql,statement>缓存,同一个sql不用再重复创建statement对象。
PreparedStatementHandler(带参数)、 CallableStatementHandler(存储过程)、 SimpleStatementHandler(简单语句|无参数)有什么区别?
SimpleStatementHandler:不会使用参数化语句查询,创建的普通statement对象,每次执行sql语句都需要数据库对sql进行预编译。
PreparedStatementHandler:
可以动态的接收参数,会把用户非法输入的单引号用\反斜杠做了转义,从而实现防止sql注入。
初次创建的开销比较大,多次处理sql时只需要初始化一次。
CallableStatementHandler:用于执行对数据库存储过程的调用,其有IN,OUT和INOUT三种类型参数(in=setXXX,out=getXXX,inout=set&get)
事务怎么实现的?
JdbcTransaction直接使用JDBC的提交和回滚事务管理机制 。它依赖与从dataSource中取得的连接connection 来管理transaction 的作用域,connection对象的获取被延迟到调用getConnection()方法。如果autocommit设置为on,开启状态的话,它会忽略commit和rollback。自己在代码中try{commit}catch{rollback}fianlly{close}实现事务。
ManagedTransaction让容器来管理事务Transaction的整个生命周期,使用ManagedTransaction的commit和rollback功能不会对事务有任何的影响,它什么都不会做,它将事务管理的权利移交给了容器来实现
//获取文件流 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// 获取SqlSession工厂 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
/** * 解析XML配置文件 * @return */ public Configuration XMLConfigBuilder.parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; // parser.evalNode("/configuration"):通过XPATH解析器,解析configuration根节点 // 从configuration根节点开始解析,最终将解析出的内容封装到Configuration对象中 parseConfiguration(parser.evalNode("/configuration")); return configuration; } private void XMLConfigBuilder.parseConfiguration(XNode root) { try { //issue #117 read properties first // 解析</properties>标签 propertiesElement(root.evalNode("properties")); // 解析</settings>标签 Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); loadCustomLogImpl(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")); 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")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
public SqlSource XMLScriptBuilder.parseScriptNode() { // 解析select\insert\ update\delete标签中的SQL语句,最终将解析到的SqlNode封装到MixedSqlNode中的List集合中 // ****将带有${}号的SQL信息封装到TextSqlNode // ****将带有#{}号的SQL信息封装到StaticTextSqlNode // ****将动态SQL标签中的SQL信息分别封装到不同的SqlNode中 MixedSqlNode rootSqlNode = parseDynamicTags(context); SqlSource sqlSource = null; // 如果SQL中包含${}和动态SQL语句,则将SqlNode封装到DynamicSqlSource if (isDynamic) { sqlSource = new DynamicSqlSource(configuration, rootSqlNode); } else { // 如果SQL中包含#{},则将SqlNode封装到RawSqlSource中,并指定parameterType sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType); } return sqlSource; } protected MixedSqlNode XMLScriptBuilder.parseDynamicTags(XNode node) { List<SqlNode> contents = new ArrayList<>(); //获取<select>\<insert>等4个标签的子节点,子节点包括元素节点和文本节点 NodeList children = node.getNode().getChildNodes(); for (int i = 0; i < children.getLength(); i++) { XNode child = node.newXNode(children.item(i)); // 处理文本节点 if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) { String data = child.getStringBody(""); // 将文本内容封装到SqlNode中 TextSqlNode textSqlNode = new TextSqlNode(data); // SQL语句中带有${}的话,就表示是dynamic的 if (textSqlNode.isDynamic()) { contents.add(textSqlNode); isDynamic = true; } else { // SQL语句中(除了${}和下面的动态SQL标签),就表示是static的 // StaticTextSqlNode的apply只是进行字符串的追加操作 contents.add(new StaticTextSqlNode(data)); } //处理元素节点 } else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628 String nodeName = child.getNode().getNodeName(); // 动态SQL标签处理器 // 思考,此处使用了哪种设计模式?---策略模式 NodeHandler handler = nodeHandlerMap.get(nodeName); if (handler == null) { throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement."); } handler.handleNode(child, contents); // 动态SQL标签是dynamic的 isDynamic = true; } } return new MixedSqlNode(contents); }
public SqlSource SqlSourceBuilder.parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) { ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters); // 创建分词解析器 GenericTokenParser parser = new GenericTokenParser("#{", "}", handler); // 解析#{} String sql = parser.parse(originalSql); // 将解析之后的SQL信息,封装到StaticSqlSource对象中 // SQL字符串是带有?号的字符串,?相关的参数信息,封装到ParameterMapping集合中 return new StaticSqlSource(configuration, sql, handler.getParameterMappings()); } public static String parse(String string, Properties variables) { VariableTokenHandler handler = new VariableTokenHandler(variables); GenericTokenParser parser = new GenericTokenParser("${", "}", handler); return parser.parse(string); }
private SqlSession DefaultSqlSessionFactory.openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { // 获取数据源环境信息 final Environment environment = configuration.getEnvironment(); // 获取事务工厂 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); // 获取JdbcTransaction或者ManagedTransaction tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 创建Executor执行器 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(); } }
private TransactionFactory DefaultSqlSessionFactory.getTransactionFactoryFromEnvironment(Environment environment) { if (environment == null || environment.getTransactionFactory() == null) { return new ManagedTransactionFactory(); } return environment.getTransactionFactory(); } // 此处以JdbcTransactionFactory为例 public Transaction Configuration.newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) { return new JdbcTransaction(ds, level, autoCommit); }
public Executor Configuration.newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { // 批处理执行器 executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { // 可重用执行器 executor = new ReuseExecutor(this, transaction); } else { // 简单执行器 executor = new SimpleExecutor(this, transaction); } // 如果开启缓存(默认是开启的),则使用缓存执行器 if (cacheEnabled) { executor = new CachingExecutor(executor); } // 插件执行 executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
new DefaultSqlSession(configuration, executor, autoCommit);
public <E> List<E> DefaultSqlSession.selectList(String statement, Object parameter, RowBounds rowBounds) { try { // 根据传入的statementId,获取MappedStatement对象 MappedStatement ms = configuration.getMappedStatement(statement); // 调用执行器的查询方法 // RowBounds是用来逻辑分页(按照条件将数据从数据库查询到内存中,在内存中进行分页) // wrapCollection(parameter)是用来装饰集合或者数组参数 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(); } }
public BoundSql DynamicSqlSource.getBoundSql(Object parameterObject) { DynamicContext context = new DynamicContext(configuration, parameterObject); // 此处会调用MixedSqlNode中包含的所有SqlNode的apply方法 // 此处会处理${},也会处理动态标签 // 最终将所有的SqlNode信息进行解析之后,追加到DynamicContext对象的StringBuilder对象中 rootSqlNode.apply(context); // 创建SQL信息解析器 SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); // 获取入参类型 Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); // 执行解析:将带有#{}的SQL语句进行解析,然后封装到StaticSqlSource中 SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings()); // 将解析后的SQL语句还有入参绑定到一起(封装到一个对象中,此时还没有将参数替换到SQL占位符?) BoundSql boundSql = sqlSource.getBoundSql(parameterObject); for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) { boundSql.setAdditionalParameter(entry.getKey(), entry.getValue()); } return boundSql; }
public CacheKey BaseExecutor.createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) { if (closed) { throw new ExecutorException("Executor was closed."); } CacheKey cacheKey = new CacheKey(); cacheKey.update(ms.getId()); cacheKey.update(rowBounds.getOffset()); cacheKey.update(rowBounds.getLimit()); cacheKey.update(boundSql.getSql()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry(); // mimic DefaultParameterHandler logic for (ParameterMapping parameterMapping : parameterMappings) { if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } cacheKey.update(value); } } if (configuration.getEnvironment() != null) { // issue #176 cacheKey.update(configuration.getEnvironment().getId()); } return cacheKey; }
public <E> List<E> CachingExecutor.query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { // 获取二级缓存 Cache cache = ms.getCache(); if (cache != null) { // 刷新二级缓存 flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, boundSql); // 从二级缓存中查询数据 @SuppressWarnings("unchecked") List<E> list = (List<E>) tcm.getObject(cache, key); // 如果二级缓存中没有查询到数据,则查询数据库 if (list == null) { // 委托给BaseExecutor执行 list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } // 委托给BaseExecutor执行 return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
public <E> List<E> BaseExecutor.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."); } 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(); } // issue #601 deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 clearLocalCache(); } } return list; }
- 执行查询之前,要给缓存设置一个占位符,查询数据库结束删除缓存,将结果集从新放入缓存,防止缓存穿透
- 执行查询时,通过configuration.newStatementHandler,创建StatementHandler(构造器初始化时,通过Configuration生成ResultSetHandler和ParameterHandler)
- 执行查询后,将结果集,存入一级缓存
private <E> List<E> BaseExecutor.queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; 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; }
public StatementHandler Configuration.newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { // 创建路由功能的StatementHandler,根据MappedStatement中的StatementType StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler); return statementHandler; } public RoutingStatementHandler.RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 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()); } }
protected Connection BaseExecutor.getConnection(Log statementLog) throws SQLException { Connection connection = transaction.getConnection(); if (statementLog.isDebugEnabled()) { return ConnectionLogger.newInstance(connection, statementLog, queryStack); } else { return connection; } }
public Statement BaseStatementHandler.prepare(Connection connection, Integer transactionTimeout) throws SQLException { ErrorContext.instance().sql(boundSql.getSql()); Statement statement = null; try { // 实例化Statement,比如PreparedStatement statement = instantiateStatement(connection); // 设置查询超时时间 setStatementTimeout(statement, transactionTimeout); setFetchSize(statement); return statement; } catch (SQLException e) { closeStatement(statement); throw e; } catch (Exception e) { closeStatement(statement); throw new ExecutorException("Error preparing statement. Cause: " + e, e); } }
public void DefaultParameterHandler.setParameters(PreparedStatement ps) { ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); // 获取要设置的参数映射信息 List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if (parameterMappings != null) { for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); // 只处理入参 if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; // 获取属性名称 String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } // 获取每个参数的类型处理器,去设置入参和获取返回值 TypeHandler typeHandler = parameterMapping.getTypeHandler(); // 获取每个参数的JdbcType JdbcType jdbcType = parameterMapping.getJdbcType(); if (value == null && jdbcType == null) { jdbcType = configuration.getJdbcTypeForNull(); } try { // 给PreparedStatement设置参数 typeHandler.setParameter(ps, i + 1, value, jdbcType); } catch (TypeException e) { throw new TypeException( "Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } catch (SQLException e) { throw new TypeException( "Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e); } } } } }
public <E> List<E> PreparedStatementHandler.query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; // 执行PreparedStatement,也就是执行SQL语句 ps.execute(); // 处理结果集 return resultSetHandler.handleResultSets(ps); }
public List<Object> DefaultResultSetHandler.handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); // <select>标签的resultMap属性,可以指定多个值,多个值之间用逗号(,)分割 final List<Object> multipleResults = new ArrayList<>(); int resultSetCount = 0; // 这里是获取第一个结果集,将传统JDBC的ResultSet包装成一个包含结果列元信息的ResultSetWrapper对象 ResultSetWrapper rsw = getFirstResultSet(stmt); // 这里是获取所有要映射的ResultMap(按照逗号分割出来的) List<ResultMap> resultMaps = mappedStatement.getResultMaps(); // 要映射的ResultMap的数量 int resultMapCount = resultMaps.size(); validateResultMapsCount(rsw, resultMapCount); // 循环处理每个ResultMap,从第一个开始处理 while (rsw != null && resultMapCount > resultSetCount) { // 得到结果映射信息 ResultMap resultMap = resultMaps.get(resultSetCount); // 处理结果集 // 从rsw结果集参数中获取查询结果,再根据resultMap映射信息,将查询结果映射到multipleResults中 handleResultSet(rsw, resultMap, multipleResults, null); rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } // 对应<select>标签的resultSets属性,一般不使用该属性 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); }
public <E> List<E> SimpleExecutor.doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { // 获取Configuration对象 Configuration configuration = ms.getConfiguration(); // 创建RoutingStatementHandler,用来处理Statement // RoutingStatementHandler类中初始化delegate类(SimpleStatementHandler、PreparedStatementHandler) StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); // 子流程1:设置参数 stmt = prepareStatement(handler, ms.getStatementLog()); // 子流程2:执行SQL语句(已经设置过参数),并且映射结果集 return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } }
private <E> List<E> BaseExecutor.queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; 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; }