Mybatis-Spring:从源码上简单查看启动执行全过程

相关依赖以及版本

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>

先通过依赖的自动配置jar的MATA-INF目录下的这两个文件进行自动装配。

至于这两个文件如何进行自动装配的,不是本次的重点。

在这里插入图片描述

根据spring.factories中的信息,查看自动装配类org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

在这里插入图片描述

1、查看MybatisAutoConfiguration

/**
类上注释:如果使用了 MapperScan 注解或者将一个配置文件指定为属性,那么将会使用这些配置。
否则这个自动配置会自动注册根配置包(启动类所在包)或配置包下定义的接口为 Mapper 
*/
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
//MybatisProperties是提供的自定义配置信息,包括mapper 文件路径、mybatis配置文件位置、执行器类型等。
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class }) // DataSourceAutoConfiguration 配置,Spring中默认的是HikariDataSource
public class MybatisAutoConfiguration implements InitializingBean {
   /* ... */
  @Override
  public void afterPropertiesSet() {
    /* ... */
  } 
    
  @Bean
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
      /* ... */
  }
    
  @Bean
  @ConditionalOnMissingBean
  public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    ExecutorType executorType = this.properties.getExecutorType();
    if (executorType != null) {
      return new SqlSessionTemplate(sqlSessionFactory, executorType);
    } else {
      return new SqlSessionTemplate(sqlSessionFactory);
    }
  }    
    
}

2、查看的sqlSessionFactory方法

这个方法返回值是SqlSession的工厂类SqlSessionFactory,而SqlSessionFactory是通过它的工厂类SqlSessionFactoryBean创建。

FactoryBean作用:如果一些复杂的bean,需要进行大量的初始化工作,可以通过把Bean实现FactoryBean<T>这个接口

// properties 对象对应 MybatisProperties 实例,即用户自定义的配置
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
  SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
  factory.setDataSource(dataSource);
  factory.setVfs(SpringBootVFS.class);
  // 配置了 Mybatis 配置文件,会加载这个配置
  if (StringUtils.hasText(this.properties.getConfigLocation())) {
    factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
  }
  applyConfiguration(factory);
  if (this.properties.getConfigurationProperties() != null) {
    factory.setConfigurationProperties(this.properties.getConfigurationProperties());
  } 
  // 获取 Spring 容器中的 Mybatis 的拦截器,
  if (!ObjectUtils.isEmpty(this.interceptors)) {
    factory.setPlugins(this.interceptors);
  }
  if (this.databaseIdProvider != null) {
    factory.setDatabaseIdProvider(this.databaseIdProvider);
  }
  // 设置配置别名
  if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
    factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
  }
  if (this.properties.getTypeAliasesSuperType() != null) {
    factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
  }
  // 设置类型处理TypeHandler包
  if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
    factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
  }
  if (!ObjectUtils.isEmpty(this.typeHandlers)) {
    factory.setTypeHandlers(this.typeHandlers);
  }
  // 设置Mapper文件路径,默认为空数组,支持 AntPath 规则
  if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
    factory.setMapperLocations(this.properties.resolveMapperLocations());
  }
  // 利用内省,获取SqlSessionFactoryBean 中是否有某些属性值,来进行添加配置
  Set<String> factoryPropertyNames = Stream
      .of(new BeanWrapperImpl(SqlSessionFactoryBean.class).getPropertyDescriptors()).map(PropertyDescriptor::getName)
      .collect(Collectors.toSet());
  Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
  if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
    // Need to mybatis-spring 2.0.2+
    factory.setScriptingLanguageDrivers(this.languageDrivers);
    if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
      defaultLanguageDriver = this.languageDrivers[0].getClass();
    }
  }
  if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
    // Need to mybatis-spring 2.0.2+
    factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
  }
  // 最后返回工厂生产的具体实例
  return factory.getObject();
}

3、查看SqlSessionFactoryBean

public class SqlSessionFactoryBean
    implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
  
  // InitializingBean 实现方法
  @Override
  public void afterPropertiesSet() throws Exception {
    notNull(dataSource, "Property 'dataSource' is required");
    notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
    state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
        "Property 'configuration' and 'configLocation' can not specified with together");

    this.sqlSessionFactory = buildSqlSessionFactory();
  }
  // FactoryBean 实现方法 
  @Override
  public SqlSessionFactory getObject() throws Exception {
    if (this.sqlSessionFactory == null) {
      afterPropertiesSet();
    }

    return this.sqlSessionFactory;
  }    
    
}

4、getObject方法

getObject方法判断sqlSessionFactory实例是否为空,如果为null,执行afterPropertiesSet方法。不为null,执行返回sqlSessionFactory

afterPropertiesSet中先判断了自定义配置信息或配置文件都为空或者都不为空,两者不能同时配置。随后调用buildSqlSessionFactory方法,初始化sqlSessionFactory

InitializingBean接口为bean提供了初始化方法,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法。

5、buildSqlSessionFactory方法

  protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
	// 具体的配置类
    final Configuration targetConfiguration;
	// 忽略的这些代码是根据 sqlSessionFactory 方法时的各个 set 配置进行添加到 targetConfiguration 中
    /* ... */

	// 配置事物管理工厂
    targetConfiguration.setEnvironment(new Environment(this.environment,
        this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory,
        this.dataSource));
    // 如果设置了mapper路径,会进行解析
    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 {
            // 解析mapper的xml,包括namespace、resultMap、sql等
            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.");
    }
    // builder 模式构建一个SqlSessionFactory
    return this.sqlSessionFactoryBuilder.build(targetConfiguration);
  }
  
  // 返回了一个DefaultSqlSessionFactory 实例
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

6、类中有另一个内部的配置类MapperScannerRegistrarNotFoundConfiguration

@org.springframework.context.annotation.Configuration
@Import(AutoConfiguredMapperScannerRegistrar.class)
// 如果容器中没有 MapperFactoryBean 和 MapperScannerConfigurer ,就会导入AutoConfiguredMapperScannerRegistrar 配置类
@ConditionalOnMissingBean({ MapperFactoryBean.class, MapperScannerConfigurer.class })
public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {

  @Override
  public void afterPropertiesSet() {
    logger.debug(
        "Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
  }

}

MybatisAutoConfiguration上的注释说明如果没有MapperScan这个注解会进行自定义配置。所以需要查看Mapperscan这个注解

7、MapperScan注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
// 导入到Spring 容器
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
    /* ... */
}

8、MapperScannerRegistrar

继承了接口ImportBeanDefinitionRegistrar ,实现registerBeanDefinitions方法,用于手动注册自定义的Bean到Spring容器中

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    // 获取启动类上的特定注解 MapperScan 的元数据信息
    AnnotationAttributes mapperScanAttrs = AnnotationAttributes
        .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    if (mapperScanAttrs != null) {
      // 如果启动类上有这个注解,根据注解的相关配置的属性执行手动注册自定义的bean到容器中
      registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
          generateBaseBeanName(importingClassMetadata, 0));
    }
  }    
}

void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
      BeanDefinitionRegistry registry, String beanName) {
    // 构建了一个 MapperScannerConfigurer 的bean定义构造器
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    // 获取 MapperScan 的各项配置进行设置
    /* ... */
    // 如果未配置扫描包信息,会获取默认的扫描位置,即启动类所在的包
    if (basePackages.isEmpty()) {
      basePackages.add(getDefaultBasePackage(annoMeta));
    }
    /* ... */
    // 注册到Spring容器中,bean名称为  启动类的完成名称#MapperScannerRegistrar#0
    registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}

9、MapperScannerConfigurer

public class MapperScannerConfigurer
    implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {
      @Override
  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    if (this.processPropertyPlaceHolders) {
      processPropertyPlaceHolders();
    }
    // 创建MapperScan的类扫描器
    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    // 填充属性
    scanner.setAddToConfig(this.addToConfig);
    scanner.setAnnotationClass(this.annotationClass);
    scanner.setMarkerInterface(this.markerInterface);
    scanner.setSqlSessionFactory(this.sqlSessionFactory);
    scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
    scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
    scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
    scanner.setResourceLoader(this.applicationContext);
    scanner.setBeanNameGenerator(this.nameGenerator);
    scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
    if (StringUtils.hasText(lazyInitialization)) {
      scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
    }
    if (StringUtils.hasText(defaultScope)) {
      scanner.setDefaultScope(defaultScope);
    }
    // 根据配置注册Mapper扫描的过滤器,并且排除了类名以 package-info 结尾
    scanner.registerFilters();
    // 扫描指定的包
    scanner.scan(
        StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }

}

10、ClassPathMapperScanner

覆盖的方法包括

// 判断当前 beanDefinition 是否是接口并且当前类可以单独实例化,如内部类、匿名类
// 即判断根据指定包名下获取的类封装的 beanDefinition 是否满足要求
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}

// 进行扫描完成后,如果扫描 beanDefinition 不为空,进行后续处理,将它们设置成 MapperFactoryBean 
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

    if (beanDefinitions.isEmpty()) {
        LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages)
                    + "' package. Please check your configuration.");
    } else {
        processBeanDefinitions(beanDefinitions);
    }

    return beanDefinitions;
}

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
    AbstractBeanDefinition definition;
    BeanDefinitionRegistry registry = getRegistry();
    // 对扫描的每一个 BeanDefinitionHolder 进行处理
    for (BeanDefinitionHolder holder : beanDefinitions) {    
        definition = (AbstractBeanDefinition) holder.getBeanDefinition();
        /* ... */
        // 扫描到的interface  作为 MapperFactoryBean 构造函数的参数
        definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
        definition.setBeanClass(this.mapperFactoryBeanClass);
        /* ... */
        // 设置MapperFactoryBean 中的属性,
        // 包括sqlSessionFactory 属性和sqlSessionTemplate属性,设置注入属性默认是根据类型注入
        // 注册到Spring 容器中
    }
}

11、MapperFactoryBean

直接看名称可以看出是FactoryBean的实现类

MapperFactoryBean继承了SqlSessionDaoSupportSqlSessionDaoSupport继承了DaoSupport,DaoSupport实现了InitializingBean接口,

@Override
public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
   // Let abstract subclasses check their configuration.
   checkDaoConfig();

   // Let concrete implementations initialize themselves.
   try {
      initDao();
   }
   catch (Exception ex) {
      throw new BeanInitializationException("Initialization of DAO failed", ex);
   }
}
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    
    
  /* ... */  
    
  // MapperFactoryBean 实现的 checkDaoConfig
  @Override
  protected void checkDaoConfig() {
    super.checkDaoConfig();
    notNull(this.mapperInterface, "Property 'mapperInterface' is required");
    Configuration configuration = getSqlSession().getConfiguration();
    // 添加到configuration 中并且configuration 中没有添加这个 mapper接口。底层用 Map 存储
    if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
      try {
        // 添加到 mapper 接口
        configuration.addMapper(this.mapperInterface);
      } catch (Exception e) {
        logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e);
        throw new IllegalArgumentException(e);
      } finally {
        ErrorContext.instance().reset();
      }
    }
  }    
  /* ... */
  
  // 返回注册到Spring容器中的bean
  @Override
  public T getObject() throws Exception {
    return getSqlSession().getMapper(this.mapperInterface);
  }
  // 返回的类是接口表示的类  
  @Override
  public Class<T> getObjectType() {
    return this.mapperInterface;
  }
}

查看addMapper方法

  public <T> void addMapper(Class<T> type) {
    if (type.isInterface()) {
      if (hasMapper(type)) {
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      boolean loadCompleted = false;
      try {
        // 使用map存储,key 为这个 mapper接口,value 类型可以看出是一个代理工厂
        knownMappers.put(type, new MapperProxyFactory<>(type));
        // It's important that the type is added before the parser is run
        // otherwise the binding may automatically be attempted by the
        // mapper parser. If the type is already known, it won't try.
        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
        parser.parse();
        loadCompleted = true;
      } finally {
        if (!loadCompleted) {
          knownMappers.remove(type);
        }
      }
    }
  }

12、查看MapperProxyFactory

public class MapperProxyFactory<T> {
  // 对应的Mapper 接口
  private final Class<T> mapperInterface;
  // mapper方法的存储
  private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
  
  // 从这个两个方法可以看出来是通过反射代理,但是是哪里调用的
  // 上面的MapperFactoryBean 实现的工厂方法 getObject 中调用获取,注册到了Spring容器中
  // 所以使用类型注入mapper接口时,获取到的实例对象
  // 这里关注的是第三个参数,即实现了 InvocationHandler 接口,进行代理的实现
  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
}

13、查看MapperProxy

public class MapperProxy<T> implements InvocationHandler, Serializable {
   // 方法存储map 
   private final Map<Method, MapperMethodInvoker> methodCache;
  /* ... */  
  @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 {
        // 真正代理执行的方法,这里也采用了map存储,如果已经有对应的值,执行直接 invoke
        // cachedInvoker 里还实现了一个功能,判断当前方法是否是默认方法,采取不同方式执行。
        return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }
   /* ... */ 
  // 内部接口,有两个内部实现类 DefaultMethodInvoker对应默认方法,
  // PlainMethodInvoker 对应mapper中的操作接口,具体看这一个
  interface MapperMethodInvoker {
    // invoke方法是需要实现的方法,PlainMethodInvoker 中是委托给了另一个类 MapperMethod 的 execute 方法
    Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable;
  }   
    
}

13、MapperMethod

public Object execute(SqlSession sqlSession, Object[] args) {
	Object result;
    switch (command.getType()) {
      // 根据类型执行      
      case INSERT: //...
      case UPDATE: //...
      case DELETE: //...
      case SELECT: 
           // 查看一种情况,select中要求返回多个值,即 list或数组
          if (method.returnsMany()) {
              // 返回值
              result = executeForMany(sqlSession, args);
          }
      //...
}
// 参数sqlSession对应在 MybatisAutoConfiguration 注册到Spring 容器中的 SqlSessionTemplate 实例 ,第二个为方法参数
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    //...
    result = sqlSession.selectList(command.getName(), param);
    //...
}

查看SqlSessionTemplate中实现

  // 委托给了一个代理类实现 ,这个代理类是在构造函数中进行初始化
  @Override
  public <E> List<E> selectList(String statement, Object parameter) {
     return this.sqlSessionProxy.selectList(statement, parameter);
  }
  // 构造函数
  public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
      PersistenceExceptionTranslator exceptionTranslator) {

    notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
    notNull(executorType, "Property 'executorType' is required");
   // 这个是MybatisAutoConfiguration 类中注册SqlSessionTemplate 的bean DefaultSqlSessionFactory 的实例
    this.sqlSessionFactory = sqlSessionFactory;
    this.executorType = executorType;
    this.exceptionTranslator = exceptionTranslator;
    // 同样查看动态代理的第三个参数,实现InvocationHandler 的类
    this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
        new Class[] { SqlSession.class }, new SqlSessionInterceptor());
  }
  
  private class SqlSessionInterceptor implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      // 根据 sqlSessionFactory 和 执行器类型 调用sqlSessionFactory的 openSession 方法创建一个SqlSession
      // 执行器类型默认是SIMPLE类型,返回的SqlSession 是 DefaultSqlSession的实例
      // sqlSession 实例执行器是SIMPLE类型,事务不自动提交
      SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
      try {
        // invoke调用sqlSession 的方法,说明这里不是对mapper接口的操作执行代理
        Object result = method.invoke(sqlSession, args);
        // 这里判断当前的sqlsession 是否是事务的,如果不是,自动提交
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
          // force commit even on non-dirty sessions because some databases require
          // a commit/rollback before calling close()
          sqlSession.commit(true);
        }
        return result;
      } catch (Throwable t) {
        /* ... */
      } finally {
        if (sqlSession != null) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }
  }

 // SqlSessionInterceptor中,并没有对查询方法进行代理操作,所以还是查看DefaultSqlSession的实例 sqlSession的selectList

跟踪到DefaultSqlSession

  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      // 这里又涉及到具体的执行器去执行。
      // 这里执行器根据缓存又分为有缓存的和没缓存的。对应CachingExecutor 和 BaseExecutor的子类。缓存这里又涉及到了Mybatis的缓存机制。缓存是对基本类型的一种代理,操作前先操作缓存
      // 根据基本类型又分为SIMPLE、BATCH和REUSE。对应SimpleExecutor、BatchExecutor和ReuseExecutor
      // 这里默认是有缓存的SIMPLE执行器,即 CachingExecutor,代理的是 
      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();
    }
  }

CachingExecutor

// 
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
  BoundSql boundSql = ms.getBoundSql(parameterObject);
  // 根据sql、参数等生成一个key
  CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
  return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

@Override
public <E> List<E> 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) {
        // 这里是查询一级缓存然后查询数据库,一级缓存是默认开启的
        // delegate就是缓存执行器所代理的基本执行器
        // 基本执行器中是查询一级缓存,如果本地缓存中未查找到,从数据库中查询,调用 queryFromDatabase
        // queryFromDatabase 包含缓存的一些操作和处理真正查询的功能 doQuery 方法
        // 这里的基本查询器是 SimpleExecutor
        list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        // 放到二级缓存中  
        tcm.putObject(cache, key, list); // issue #578 and #116
      }
      return list;
    }
  }
  return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

跟踪SimpleExecutor中调用

public class SimpleExecutor extends BaseExecutor {
  /* ... */   
    
  @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,这里的类分为 SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler。默认是PreparedStatementHandler 即预编译的
      // 对应的jdbc的statement 为 Statement、PreparedStatement和 CallableStatement
      // 这里就是内部调用JDBC api实现数据库的查询
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }
  /* ... */ 
}

最后提及一个Configuration

  // 执行器类型包括 SIMPLE、REUSE、BATCH,在枚举类 ExecutorType 中定义。默认是 SIMPLE 类型
  // SIMPLE: 这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句,用完立刻关闭Statement对象
  // REUSE: 这个执行器类型会复用预处理语句。
  // BATCH: 这个执行器会批量执行所有更新语句
  protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
  public Executor newExecutor(Transaction transaction) {
    return newExecutor(transaction, defaultExecutorType);
  }

  public Executor 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;
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值