相关依赖以及版本
<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
继承了SqlSessionDaoSupport
,SqlSessionDaoSupport
继承了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;
}