一、架构了解

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功能不会对事务有任何的影响,它什么都不会做,它将事务管理的权利移交给了容器来实现

 
三、通过DEBUG,查看执行流程,找到以上问题
一、解析配置
1、获取配置文件流
//获取文件流
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
2、解析配置
  2.1、通过SqlSessionFactoryBuilder.build()方法解析配置文件,得到SqlSessionFactory其中包含Configuration对象
// 获取SqlSession工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  2.2、通过XPath将文件流解析为Node节点
/**
 * 解析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);
  }
}
  2.3、ognl表达式,解析动态sql的判断结果
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);
}
  2.4、使用分词解析器(GenericTokenParser)解析sql中的参数,并将?相关的参数信息,封装到ParameterMapping集合中
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);
}
二、获取SqlSession
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();
  }
}
  3、生成事务工厂,创建事务
     JdbcTransactionFactory、ManagedTransactionFactory、SpringTransactionFactory
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);
}
  4、创建Excetor处理器
    通过事务和处理器类型,使用Configuration.newExecutor创建处理器Excutor,如果开启了缓存那么创建缓存执行器(CachingExecutor),如果指定了(BatchExecutor|ReuseExecutor|SimpleExecutor),那么使用指定的执行器,默认使用简单执行器(SimpleExecutor)
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;
}
  5、创建DefaultSqlSession
new DefaultSqlSession(configuration, executor, autoCommit);
三、执行语句
  6、根据传入的statementId,获取MappedStatement对象,对象从Configuration.mappedStatements中匹配
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();
   }
}
  7、通过SqlSource.getBoundSql()获取绑定的sql语句,以及将所有的入参封装成对应sql的ParameterMapping集合,得到BoundSql对象。(此时还没有将参数替换到SQL占位符)
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;
}
  8、生成缓存Key
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;
}
  9、由于二级缓存是mapper级别的,所以通过MapperdStatement.catch()获取二级缓存
    缓存对象不为空,取缓存数据,缓存结果是空,或者缓存对象是空都委托给BaseExecutor继续执行(根据MapperdStatement的flushCacheRequired判断是否需要刷新二级缓存,刷新的话,就清空事务缓存管理的缓存)
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);
 }
  10、BaseExecutor先取一级缓存,一级缓存有数据,取一级缓存,没有则查询数据库
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;
}
  11、执行查询
  • 执行查询之前,要给缓存设置一个占位符,查询数据库结束删除缓存,将结果集从新放入缓存,防止缓存穿透
  • 执行查询时,通过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;
}
  12、获取StatementHandler
    通过RoutingStatementHandler路由到对应的StatementHandler,实例化statement(PreparedStatement、Statement、CallableStatement)
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());
  }

}
  13、获取连接connection(使用jdbc或者容器的事务管理机制实现事务)
protected Connection BaseExecutor.getConnection(Log statementLog) throws SQLException {
  Connection connection = transaction.getConnection();
  if (statementLog.isDebugEnabled()) {
    return ConnectionLogger.newInstance(connection, statementLog, queryStack);
  } else {
    return connection;
  }
}
  14、使用装饰模式,通过RoutingStatementHandler路由到对应的StatementHandler,实例化statement(PreparedStatement、Statement、CallableStatement)
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);
  }
}
  15、通过ParameterHandler处理参数,处理入参,匹配属性名称,通过类型处理器设置入参
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);
            }
         }
      }
   }
}
  16、statement.execute()执行语句,得到结果集
public <E> List<E> PreparedStatementHandler.query(Statement statement, ResultHandler resultHandler) throws SQLException {
  PreparedStatement ps = (PreparedStatement) statement;
  // 执行PreparedStatement,也就是执行SQL语句
  ps.execute();
  // 处理结果集
  return resultSetHandler.handleResultSets(ps);
}
  17、使用反射机制,将结果集映射到实体对象中。
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);
}
  18、关闭statement
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);
   }
}
  19、更新一级缓存
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;
}

 

posted on 2023-03-10 09:54  浅灰色的记忆  阅读(41)  评论(0编辑  收藏  举报