Mybatis3.5.1源码分析
- Mybatis-SqlSessionFactoryBuilder,XMLConfigBuilder,XPathParser源码解析
- Mybatis-Configuration源码解析
- Mybatis-事务对象源码解析
- Mybatis-数据源源码解析
- Mybatis缓存策略源码解析
- Mybatis-DatabaseIdProvider源码解析
- Mybatis-TypeHandler源码解析
- Mybatis-Reflector源码解析
- Mybatis-ObjectFactory,ObjectWrapperFactory源码分析
- Mybatis-Mapper各类标签封装类源码解析
- Mybatis-XMLMapperBuilder,XMLStatmentBuilder源码分析
- Mybatis-MapperAnnotationBuilder源码分析
- [Mybatis-MetaObject,MetaClass源码解析]https://www.jianshu.com/p/f51fa552f30a)
- Mybatis-LanguageDriver源码解析
- Mybatis-SqlSource源码解析
- Mybatis-SqlNode源码解析
- Mybatis-KeyGenerator源码解析
- Mybatis-Executor源码解析
- Mybatis-ParameterHandler源码解析
- Mybatis-StatementHandler源码解析
- Mybatis-DefaultResultSetHandler(一)源码解析
- Mybatis-DefaultResultSetHandler(二)源码解析
- Mybatis-ResultHandler,Cursor,RowBounds 源码分析
- Mybatis-MapperProxy源码解析
- Mybatis-SqlSession源码解析
- Mybatis-Interceptor源码解析
Configuration
/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.session;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.function.BiFunction;
import org.apache.ibatis.binding.MapperRegistry;
import org.apache.ibatis.builder.CacheRefResolver;
import org.apache.ibatis.builder.IncompleteElementException;
import org.apache.ibatis.builder.ResultMapResolver;
import org.apache.ibatis.builder.annotation.MethodResolver;
import org.apache.ibatis.builder.xml.XMLStatementBuilder;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.decorators.FifoCache;
import org.apache.ibatis.cache.decorators.LruCache;
import org.apache.ibatis.cache.decorators.SoftCache;
import org.apache.ibatis.cache.decorators.WeakCache;
import org.apache.ibatis.cache.impl.PerpetualCache;
import org.apache.ibatis.datasource.jndi.JndiDataSourceFactory;
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
import org.apache.ibatis.executor.BatchExecutor;
import org.apache.ibatis.executor.CachingExecutor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ReuseExecutor;
import org.apache.ibatis.executor.SimpleExecutor;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.loader.ProxyFactory;
import org.apache.ibatis.executor.loader.cglib.CglibProxyFactory;
import org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl;
import org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl;
import org.apache.ibatis.logging.log4j.Log4jImpl;
import org.apache.ibatis.logging.log4j2.Log4j2Impl;
import org.apache.ibatis.logging.nologging.NoLoggingImpl;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMap;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.InterceptorChain;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.scripting.LanguageDriverRegistry;
import org.apache.ibatis.scripting.defaults.RawLanguageDriver;
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeAliasRegistry;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
/**
* Mybatis总配置信息类。
* @author Clinton Begin
*/
public class Configuration {
protected Environment environment;
/**
* 允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。
*/
protected boolean safeRowBoundsEnabled;
/**
* 允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为 false。
*/
protected boolean safeResultHandlerEnabled = true;
/**
* 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。
*/
protected boolean mapUnderscoreToCamelCase;
/**
* 当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载(参考 lazyLoadTriggerMethods)。
* 默认为false (在 3.4.1 及之前的版本默认值为 true)
*/
protected boolean aggressiveLazyLoading;
/**
* 是否允许单一语句返回多结果集(需要驱动支持)。
*/
protected boolean multipleResultSetsEnabled = true;
/**
* 允许 JDBC 支持自动生成主键,需要驱动支持。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能支持但仍可正常工作(比如 Derby)
*/
protected boolean useGeneratedKeys;
/**
* 使用列标签代替列名。不同的驱动在这方面会有不同的表现,具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。
*
* isUseColumnLabel,默认为true。根据Javadoc,这个ColumnLabel就是AS后的那个名字,如果没有AS的话,就是获取的原生的字段名
*
*/
protected boolean useColumnLabel = true;
/**
* 全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。默认开启
*/
protected boolean cacheEnabled = true;
/**
* 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,
* 这在依赖于 Map.keySet() 或 null 值初始化的时候比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。
*/
protected boolean callSettersOnNulls;
/**
* 允许使用构造函数的参数名作为语句参数名称。
* 为了使用该特性,你的项目必须采用 Java 8 编译。
*/
protected boolean useActualParamName = true;
/**
* 当返回行的所有列都是空时,MyBatis默认返回 null。
* 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (如集合或关联)。(新增于 3.4.2)
*/
protected boolean returnInstanceForEmptyRow;
/**
* 指定 MyBatis 增加到日志名称的前缀。
*/
protected String logPrefix;
protected Class extends Log> logImpl;
/**
* VFS(virtual File System)的作用就是采用标准的Unix系统调用读写位于不同物理介质上的不同文件系统,
* 即为各类文件系统提供了一个统一的操作界面和应用编程接口
*/
protected Class extends VFS> vfsImpl;
/**
* 本地缓存作用域
*
* - LocalCacheScope.SESSION:数据库对象
* - LocalCacheScope.STATEMENT:SQL腳本
*
*/
protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
/**
* null对应jdbcType
*/
protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
/**
* 指定哪个对象的方法触发一次延迟加载。默认方法为:equals,clone,hashCode,toString
*/
protected Set lazyLoadTriggerMethods = new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString"));
/**
*设置超时时间,它决定驱动等待数据库响应的秒数。
*/
protected Integer defaultStatementTimeout;
/**
* 为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖。
*/
protected Integer defaultFetchSize;
/**
* 配置默认的执行器。
*
* - SIMPLE 就是普通的执行器,默认;
* - REUSE 执行器会重用预处理语句(prepared statements);
* - BATCH 执行器将重用语句并执行批量更新
*
*/
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
/**
* 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;
* PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。
*/
protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
/**
* 指定发现自动映射目标未知列(或者未知属性类型)的行为。
*
* - AutoMappingUnknownColumnBehavior.NONE:不做任何反应
* - AutoMappingUnknownColumnBehavior.WARNING:输出提醒日志
* - AutoMappingUnknownColumnBehavior.FAILING:映射失败 (抛出 SqlSessionException)
*
*/
protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
protected Properties variables = new Properties();
protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
protected ObjectFactory objectFactory = new DefaultObjectFactory();
protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
/**
* 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。
*/
protected boolean lazyLoadingEnabled = false;
/**
* Javassist代理工厂
*/
protected ProxyFactory proxyFactory = new JavassistProxyFactory(); // #224 Using internal Javassist instead of OGNL
/**
* 当前项目引用的dataBaseId
*
* dataBaseId的作用:使得引用mybatis的项目,根据不同的数据库进行编写对应的数据库SQL
*
*/
protected String databaseId;
/**
* 用户获取数据库连接的工厂类
* Configuration factory class.
* Used to create Configuration for loading deserialized unread properties.
* 用于创建配置加载反序列化未读属性。;
* @see Issue 300 (google code)
*/
protected Class> configurationFactory;
/**
* 映射器 注册类
*/
protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
/**
* 拦截器链
*/
protected final InterceptorChain interceptorChain = new InterceptorChain();
/**
* 类型 处理 注册器
*/
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
/**
* 类型别名注册器
*/
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
/**
* 语言驱动注册器
*/
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
/**
* 存放着SQL的StrictMap
*/
protected final Map mappedStatements = new StrictMap("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
/**
* Mapper.xml的命名空间 - Cache实例【是一个经历了一层又一层装饰得到的装饰类】
*/
protected final Map caches = new StrictMap<>("Caches collection");
/**
* resultMap的StrictMap
*/
protected final Map resultMaps = new StrictMap<>("Result Maps collection");
/**
* Mapper.xml的ParameterMap标签信息。 key=ParameterMap标签的ID,value=ParameterMap标签的内容。
*/
protected final Map parameterMaps = new StrictMap<>("Parameter Maps collection");
/**
* KeyGentertos的StrictMap
*/
protected final Map keyGenerators = new StrictMap<>("Key Generators collection");
/**
* 加载资源,就是mapper.xml
*/
protected final Set loadedResources = new HashSet<>();
/**
* SQL片段
*/
protected final Map sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");
/**
* XML Statment 构建类 集合LinkedList
*/
protected final Collection incompleteStatements = new LinkedList<>();
/**
* 解析CacheRef失败的{@link CacheRefResolver} 集合LinkedList
*/
protected final Collection incompleteCacheRefs = new LinkedList<>();
/**
* 结果映射解析 集合LinkedList,存放着构建ResultMap时抛出BuilderException异常的resultMapResolver实例
*/
protected final Collection incompleteResultMaps = new LinkedList<>();
/**
* 方法映射解析 集合LinkedList
*/
protected final Collection incompleteMethods = new LinkedList<>();
/*
* A map holds cache-ref relationship. The key is the namespace that
* references a cache bound to another namespace and the value is the
* namespace which the actual cache is bound to.
*/
protected final Map cacheRefMap = new HashMap<>();
public Configuration(Environment environment) {
this();
this.environment = environment;
}
/**
* Mybatis配置类。初始化Mybatix的配置和工厂类,一些工具类的别名,语言驱动
*/
public Configuration() {
//事务工厂
//JDBC事务工厂
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
//ManagedTransaction:MyBatis自身不会去实现事务管理,而是让程序的容器如(JBOSS,Weblogic)来实现对事务的管理
//生成MangaedTransaction工厂
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
//数据源工厂
//jndi的数据源,参考博客:https://blog.csdn.net/reliveit/article/details/45136297
typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
//生产具有简单,同步,线程安全数据库连接池的数据源工厂
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
//生产无连接池数据源(即每次获取请求都简单的打开和关闭连接)工厂
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
//缓存策略
//永久缓存 Cache接口实现类,里面就是维护着一个HashMap
typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
//使用先进先出缓存策略的缓存装饰类
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
//使用最近最少使用的缓存策略的缓存装饰类
typeAliasRegistry.registerAlias("LRU", LruCache.class);
// 软引用回收策略 缓存装饰类
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
// 弱引用回收策略 缓存装饰类
typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
/**
* 供应商的数据库Id提供者
* 它会返回数据库产品名称作为数据库ID.
* 如果使用用户提供一个属性列表,它会使用这个属性列表去转化数据库产品名
* 如:key='Microsoft SQL Server',value='ms',就会返回'ms'.
* 如果没有数据库产品名或者指定了属性列表当但是没有找到译文,就会返回null.
*/
typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
/**
* XML语言驱动
*
* Mybatis默认XML驱动类为XMLLanguageDriver,其主要作用于解析select|update|insert|delete节点为完整的SQL语句。
*
*/
typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
//这是一个简单的语言驱动,只能针对静态SQL的处里,如果出现动态SQL标签如
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);
//下面是日志别名
typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);
//动态代理工厂,针对懒加载的
//CGLIB代理工厂
typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
//Javassist代理工厂
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);
//设置默认的语言驱动为XMLLanguagerDriver
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
//注册RawLanguageDriver语言驱动
languageRegistry.register(RawLanguageDriver.class);
}
public String getLogPrefix() {
return logPrefix;
}
public void setLogPrefix(String logPrefix) {
this.logPrefix = logPrefix;
}
public Class extends Log> getLogImpl() {
return logImpl;
}
/**
* 传递logImpl给LogFactory调用
* @param logImpl
*/
public void setLogImpl(Class extends Log> logImpl) {
if (logImpl != null) {
this.logImpl = logImpl;
LogFactory.useCustomLogging(this.logImpl);
}
}
public Class extends VFS> getVfsImpl() {
return this.vfsImpl;
}
public void setVfsImpl(Class extends VFS> vfsImpl) {
if (vfsImpl != null) {
this.vfsImpl = vfsImpl;
VFS.addImplClass(this.vfsImpl);
}
}
public boolean isCallSettersOnNulls() {
return callSettersOnNulls;
}
public void setCallSettersOnNulls(boolean callSettersOnNulls) {
this.callSettersOnNulls = callSettersOnNulls;
}
/**
*
* @return {@see #AutoMappingUnknownColumnBehavior}
*/
public boolean isUseActualParamName() {
return useActualParamName;
}
public void setUseActualParamName(boolean useActualParamName) {
this.useActualParamName = useActualParamName;
}
public boolean isReturnInstanceForEmptyRow() {
return returnInstanceForEmptyRow;
}
public void setReturnInstanceForEmptyRow(boolean returnEmptyInstance) {
this.returnInstanceForEmptyRow = returnEmptyInstance;
}
public String getDatabaseId() {
return databaseId;
}
public void setDatabaseId(String databaseId) {
this.databaseId = databaseId;
}
public Class> getConfigurationFactory() {
return configurationFactory;
}
public void setConfigurationFactory(Class> configurationFactory) {
this.configurationFactory = configurationFactory;
}
public boolean isSafeResultHandlerEnabled() {
return safeResultHandlerEnabled;
}
public void setSafeResultHandlerEnabled(boolean safeResultHandlerEnabled) {
this.safeResultHandlerEnabled = safeResultHandlerEnabled;
}
public boolean isSafeRowBoundsEnabled() {
return safeRowBoundsEnabled;
}
public void setSafeRowBoundsEnabled(boolean safeRowBoundsEnabled) {
this.safeRowBoundsEnabled = safeRowBoundsEnabled;
}
public boolean isMapUnderscoreToCamelCase() {
return mapUnderscoreToCamelCase;
}
public void setMapUnderscoreToCamelCase(boolean mapUnderscoreToCamelCase) {
this.mapUnderscoreToCamelCase = mapUnderscoreToCamelCase;
}
/**
* 将{@code resource} 添加到已加载资源集合理
* @param resource 资源路径
*/
public void addLoadedResource(String resource) {
loadedResources.add(resource);
}
/**
* 查询已加载资源的集合里有没有{@code resource}
* @param resource 资源路径
* @return 如果有,返回true;否则,返回false
*/
public boolean isResourceLoaded(String resource) {
return loadedResources.contains(resource);
}
public Environment getEnvironment() {
return environment;
}
public void setEnvironment(Environment environment) {
this.environment = environment;
}
public AutoMappingBehavior getAutoMappingBehavior() {
return autoMappingBehavior;
}
public void setAutoMappingBehavior(AutoMappingBehavior autoMappingBehavior) {
this.autoMappingBehavior = autoMappingBehavior;
}
/**
* @since 3.4.0
*/
public AutoMappingUnknownColumnBehavior getAutoMappingUnknownColumnBehavior() {
return autoMappingUnknownColumnBehavior;
}
/**
* @since 3.4.0
*/
public void setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior) {
this.autoMappingUnknownColumnBehavior = autoMappingUnknownColumnBehavior;
}
/**
* 延迟加载的全局开关
* @return {@link Configuration#lazyLoadingEnabled}
*/
public boolean isLazyLoadingEnabled() {
return lazyLoadingEnabled;
}
public void setLazyLoadingEnabled(boolean lazyLoadingEnabled) {
this.lazyLoadingEnabled = lazyLoadingEnabled;
}
public ProxyFactory getProxyFactory() {
return proxyFactory;
}
public void setProxyFactory(ProxyFactory proxyFactory) {
if (proxyFactory == null) {
proxyFactory = new JavassistProxyFactory();
}
this.proxyFactory = proxyFactory;
}
public boolean isAggressiveLazyLoading() {
return aggressiveLazyLoading;
}
public void setAggressiveLazyLoading(boolean aggressiveLazyLoading) {
this.aggressiveLazyLoading = aggressiveLazyLoading;
}
public boolean isMultipleResultSetsEnabled() {
return multipleResultSetsEnabled;
}
public void setMultipleResultSetsEnabled(boolean multipleResultSetsEnabled) {
this.multipleResultSetsEnabled = multipleResultSetsEnabled;
}
public Set getLazyLoadTriggerMethods() {
return lazyLoadTriggerMethods;
}
public void setLazyLoadTriggerMethods(Set lazyLoadTriggerMethods) {
this.lazyLoadTriggerMethods = lazyLoadTriggerMethods;
}
public boolean isUseGeneratedKeys() {
return useGeneratedKeys;
}
public void setUseGeneratedKeys(boolean useGeneratedKeys) {
this.useGeneratedKeys = useGeneratedKeys;
}
public ExecutorType getDefaultExecutorType() {
return defaultExecutorType;
}
public void setDefaultExecutorType(ExecutorType defaultExecutorType) {
this.defaultExecutorType = defaultExecutorType;
}
public boolean isCacheEnabled() {
return cacheEnabled;
}
public void setCacheEnabled(boolean cacheEnabled) {
this.cacheEnabled = cacheEnabled;
}
public Integer getDefaultStatementTimeout() {
return defaultStatementTimeout;
}
public void setDefaultStatementTimeout(Integer defaultStatementTimeout) {
this.defaultStatementTimeout = defaultStatementTimeout;
}
/**
* @since 3.3.0
*/
public Integer getDefaultFetchSize() {
return defaultFetchSize;
}
/**
* @since 3.3.0
*/
public void setDefaultFetchSize(Integer defaultFetchSize) {
this.defaultFetchSize = defaultFetchSize;
}
public boolean isUseColumnLabel() {
return useColumnLabel;
}
public void setUseColumnLabel(boolean useColumnLabel) {
this.useColumnLabel = useColumnLabel;
}
public LocalCacheScope getLocalCacheScope() {
return localCacheScope;
}
public void setLocalCacheScope(LocalCacheScope localCacheScope) {
this.localCacheScope = localCacheScope;
}
public JdbcType getJdbcTypeForNull() {
return jdbcTypeForNull;
}
public void setJdbcTypeForNull(JdbcType jdbcTypeForNull) {
this.jdbcTypeForNull = jdbcTypeForNull;
}
public Properties getVariables() {
return variables;
}
public void setVariables(Properties variables) {
this.variables = variables;
}
public TypeHandlerRegistry getTypeHandlerRegistry() {
return typeHandlerRegistry;
}
/**
* Set a default {@link TypeHandler} class for {@link Enum}.
* A default {@link TypeHandler} is {@link org.apache.ibatis.type.EnumTypeHandler}.
* @param typeHandler a type handler class for {@link Enum}
* @since 3.4.5
*/
public void setDefaultEnumTypeHandler(Class extends TypeHandler> typeHandler) {
if (typeHandler != null) {
getTypeHandlerRegistry().setDefaultEnumTypeHandler(typeHandler);
}
}
public TypeAliasRegistry getTypeAliasRegistry() {
return typeAliasRegistry;
}
/**
* @since 3.2.2
*/
public MapperRegistry getMapperRegistry() {
return mapperRegistry;
}
public ReflectorFactory getReflectorFactory() {
return reflectorFactory;
}
public void setReflectorFactory(ReflectorFactory reflectorFactory) {
this.reflectorFactory = reflectorFactory;
}
public ObjectFactory getObjectFactory() {
return objectFactory;
}
public void setObjectFactory(ObjectFactory objectFactory) {
this.objectFactory = objectFactory;
}
public ObjectWrapperFactory getObjectWrapperFactory() {
return objectWrapperFactory;
}
public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) {
this.objectWrapperFactory = objectWrapperFactory;
}
/**
* @since 3.2.2
*/
public List getInterceptors() {
return interceptorChain.getInterceptors();
}
/**
*
* @return {@see languageRegistry}
*/
public LanguageDriverRegistry getLanguageRegistry() {
return languageRegistry;
}
/**
* 设置并注册默认的语言驱动
* @param driver 如果为null,就会使用 {@link XMLLanguageDriver} 作为默认的语言驱动
*/
public void setDefaultScriptingLanguage(Class extends LanguageDriver> driver) {
if (driver == null) {
driver = XMLLanguageDriver.class;
}
getLanguageRegistry().setDefaultDriverClass(driver);
}
public LanguageDriver getDefaultScriptingLanguageInstance() {
return languageRegistry.getDefaultDriver();
}
/**
* 获取语言驱动
*
* 当 {@code langClass} 为null,会取默认的语言驱动;当 {@code langClass} 不为null,获取
* 构建langeClass的实例,并存在到 {@link #languageRegistry} 中
*
* @since 3.5.1
* @param langClass 语言驱动类
*/
public LanguageDriver getLanguageDriver(Class extends LanguageDriver> langClass) {
//langClass为null时获取默认的语言驱动
if (langClass == null) {
return languageRegistry.getDefaultDriver();
}
//注册并构建langClass实例
languageRegistry.register(langClass);
//获取langClass的实例
return languageRegistry.getDriver(langClass);
}
/**
* @deprecated Use {@link #getDefaultScriptingLanguageInstance()}
*/
@Deprecated
public LanguageDriver getDefaultScriptingLanuageInstance() {
return getDefaultScriptingLanguageInstance();
}
/**
* 构造 {@code object} 的元对象
* @param object 对象
* @return {@code object} 的元对象
*/
public MetaObject newMetaObject(Object object) {
return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}
/**
* 构建参数处理器
* @param mappedStatement Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
* @param parameterObject 参数对象
* @param boundSql 参数映射与可执行SQL封装类对象
* @return {@code mappedStatement}默认的语言的驱动为 XMLLanguageDriver,而XMLLanguageDriver创建的是
* ParameterHandler接口实例是DefaultParameteHandler,该DefaultParmaeterHandler还会经过拦截器链的包装后才返回出去
*/
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
//mappedStatement.getLang():语言驱动,默认是 {@link org.apache.ibatis.scripting.xmltags.XMLLanguageDriver}
//XMLLanguageDriver.createParamHandler默认是创建DefaultParameteHandler
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
//将resultSetHandler交给拦截器链加以包装
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
//返回经过拦截器链包装后的parameterHandler
return parameterHandler;
}
/**
* 新建一个 {@link ResultSetHandler}
* @param executor 执行器
* @param mappedStatement Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
* @param rowBounds Mybatis的分页对象
* @param parameterHandler 参数处理器
* @param resultHandler 结果处理器
* @param boundSql 参数映射与可执行SQL封装类对象
* @return 经过拦截器链包装后的DefaultResultSetHandler
*/
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
//初始化默认结果集处理器
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
//将resultSetHandler交给拦截器链加以包装
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
//返回经过拦截器链包装后的resultSetHandler
return resultSetHandler;
}
/**
* 新建一个 {@link StatementHandler},
* @param executor 执行器
* @param mappedStatement Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
* @param parameterObject 参数对象
* @param rowBounds Mybatis的分页对象
* @param resultHandler 结果接收处理对象
* @param boundSql 参数映射与可执行SQL封装类对象
* @return 经过拦截器链包装后的RoutingStatementHandler
*/
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
/**
* RountingStatementHandler:一个具体实现类,这个类中并没有对Statement对象具体使用,还是根据得到Excutor类型,
* 决定创建何种类型StatementHandler对象。在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象
*/
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
//将statementHandler交给拦截器链加以包装
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
//返回经过拦截器链包装后的statementHandler
return statementHandler;
}
public Executor newExecutor(Transaction transaction) {
return newExecutor(transaction, defaultExecutorType);
}
/**
* 新建执行器
* @param transaction 事务对象
* @param executorType 执行器类型
* @return {@code executorType} 指定的执行器实例,默认为SimpleExecutor
*/
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
//如果executorType,取默认defaultExecutorType,defaultExecutorType为 ExecutorType.SIMPLE
executorType = executorType == null ? defaultExecutorType : executorType;
//如果executorType还是为空,就是赋值为 ExecutorType.SIMPLE
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);
}
//cacheEnabled:全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。默认开启
if (cacheEnabled) {
//使用CachingExecutor装饰executor
executor = new CachingExecutor(executor);
}
//将执行器添加到拦截器链中,并回调拦截链的拦截器的plugin方法。
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
/**
* 添加 KeyGenerator对象
* @param id KeyGenerator对应的ID
* @param keyGenerator KeyGenerator对象
*/
public void addKeyGenerator(String id, KeyGenerator keyGenerator) {
//将id和keyGenerator添加到keyGenerators
keyGenerators.put(id, keyGenerator);
}
public Collection getKeyGeneratorNames() {
return keyGenerators.keySet();
}
public Collection getKeyGenerators() {
return keyGenerators.values();
}
/**
* 获取 {@code id} 对应的 KeyGenerator对象
* @param id DML标签ID+SelectKeyGenerator.SELECT_KEY_SUFFIX;
* @return {@code id} 对应的 KeyGenerator对象
*/
public KeyGenerator getKeyGenerator(String id) {
return keyGenerators.get(id);
}
public boolean hasKeyGenerator(String id) {
return keyGenerators.containsKey(id);
}
public void addCache(Cache cache) {
caches.put(cache.getId(), cache);
}
public Collection getCacheNames() {
return caches.keySet();
}
public Collection getCaches() {
return caches.values();
}
/**
* 获取{@link @id}对应的缓存
*/
public Cache getCache(String id) {
return caches.get(id);
}
/**
* 判断是否存在{@link @id}对应的缓存
*/
public boolean hasCache(String id) {
return caches.containsKey(id);
}
public void addResultMap(ResultMap rm) {
resultMaps.put(rm.getId(), rm);
checkLocallyForDiscriminatedNestedResultMaps(rm);
checkGloballyForDiscriminatedNestedResultMaps(rm);
}
public Collection getResultMapNames() {
return resultMaps.keySet();
}
public Collection getResultMaps() {
return resultMaps.values();
}
/**
* 根据 id 从 {@link #resultMaps} 获取对应的 ResultMap对象
* @param id resultMap的Id
* @return resultMap对象
*/
public ResultMap getResultMap(String id) {
return resultMaps.get(id);
}
public boolean hasResultMap(String id) {
return resultMaps.containsKey(id);
}
public void addParameterMap(ParameterMap pm) {
parameterMaps.put(pm.getId(), pm);
}
public Collection getParameterMapNames() {
return parameterMaps.keySet();
}
public Collection getParameterMaps() {
return parameterMaps.values();
}
public ParameterMap getParameterMap(String id) {
return parameterMaps.get(id);
}
public boolean hasParameterMap(String id) {
return parameterMaps.containsKey(id);
}
public void addMappedStatement(MappedStatement ms) {
mappedStatements.put(ms.getId(), ms);
}
public Collection getMappedStatementNames() {
buildAllStatements();
return mappedStatements.keySet();
}
public Collection getMappedStatements() {
buildAllStatements();
return mappedStatements.values();
}
public Collection getIncompleteStatements() {
return incompleteStatements;
}
public void addIncompleteStatement(XMLStatementBuilder incompleteStatement) {
incompleteStatements.add(incompleteStatement);
}
/**
* 获取解析CacheRef失败的{@link CacheRefResolver}
*/
public Collection getIncompleteCacheRefs() {
return incompleteCacheRefs;
}
/**
* 添加解析CacheRef失败的{@link CacheRefResolver},推测用于统计报告
*/
public void addIncompleteCacheRef(CacheRefResolver incompleteCacheRef) {
incompleteCacheRefs.add(incompleteCacheRef);
}
public Collection getIncompleteResultMaps() {
return incompleteResultMaps;
}
/**
* 添加构建ResultMap时抛出异常的resultMapResolver实例
* @param resultMapResolver 构建ResultMap时抛出异常的resultMapResolver实例
*/
public void addIncompleteResultMap(ResultMapResolver resultMapResolver) {
incompleteResultMaps.add(resultMapResolver);
}
public void addIncompleteMethod(MethodResolver builder) {
incompleteMethods.add(builder);
}
public Collection getIncompleteMethods() {
return incompleteMethods;
}
public MappedStatement getMappedStatement(String id) {
return this.getMappedStatement(id, true);
}
/**
* 根据 {@code id} 获取对应的MappedStatement对象
* @param id MappedStatmentId,即DML标签ID
* @param validateIncompleteStatements 是否重新构建未成功构建的Statements
* @return MappedStatement对象
*/
public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
if (validateIncompleteStatements) {
buildAllStatements();
}
return mappedStatements.get(id);
}
public Map getSqlFragments() {
return sqlFragments;
}
/**
* 添加拦截器到拦截器链
* @param interceptor
*/
public void addInterceptor(Interceptor interceptor) {
interceptorChain.addInterceptor(interceptor);
}
/**
* 将 {@code packageName}的继承 {@code superType} 的 Mapper.xml对应的接口类 加入到mapperRegistry中
* @param packageName Mapper.xml对应的接口类所在包的包名
* @param superType Mapper.xml对应的接口类要继承的父类
*/
public void addMappers(String packageName, Class> superType) {
mapperRegistry.addMappers(packageName, superType);
}
/**
* 将 {@code packageName}的 Mapper.xml对应的接口类 加入到mapperRegistry中
* @param packageName Mapper.xml对应的接口类所在包的包名
*/
public void addMappers(String packageName) {
mapperRegistry.addMappers(packageName);
}
/**
* 将 Mapper.xml对应的接口类 加入到mapperRegistry中
* @param type Mapper.xml对应的接口类
*/
public void addMapper(Class type) {
mapperRegistry.addMapper(type);
}
/**
* 从mapperRegistry获取 Mapper.xml对应的接口类对象
* @param type Mapper.xml对应的接口类
* @param sqlSession 数据库对话对象
*/
public T getMapper(Class type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
/**
* 判断是否 {@code type} 是否存在mapperRegistry中
* @param type Mapper.xml对应的接口类
* @return 存在为true;否则为false
*/
public boolean hasMapper(Class> type) {
return mapperRegistry.hasMapper(type);
}
public boolean hasStatement(String statementName) {
return hasStatement(statementName, true);
}
/**
* {@code statementName} 是否存在 {@link #mappedStatements} 中
* @param statementName Mapper.xml的Delect|insert|update|delete 标签Id
* @param validateIncompleteStatements 验证不完整的Statements.若为true,对mybatis全局配置信息中以incomple*命名的相关集合中的元素实例重新进行解析。
* @return
*/
public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {
if (validateIncompleteStatements) {
buildAllStatements();
}
return mappedStatements.containsKey(statementName);
}
public void addCacheRef(String namespace, String referencedNamespace) {
cacheRefMap.put(namespace, referencedNamespace);
}
/**
* 对mybatis全局配置信息中以incomple*命名的相关集合中的元素实例重新进行解析。
*
* 所有以incomple*命名的相关集合的元素实例如果重新解析成功将会从集合中移除,
* 但如果是incompleteResultMaps如果有一个解析失败都会抛出异常。
*
*
* Parses all the unprocessed statement nodes in the cache. It is recommended
* to call this method once all the mappers are added as it provides fail-fast
* statement validation.
*
* 译文:解析在缓存中所有未处理的Statement实例.建议一旦所有的映射器添加调用这个方法,
* 因为它提供了快速失败声明验证。;
*
*/
protected void buildAllStatements() {
/**
* 重新解析存放在 {@link #incompleteResultMaps} 中的 {@link ResultMapResolver} 实例。
* 还是解析失败,就会抛出异常。
*/
parsePendingResultMaps();
/**
* 重新解析存放在 {@link #incompleteCacheRefs} 中的 {@link CacheRefResolver} 实例。
* 将重新解析成功CacheRefResolver实例移除
*/
if (!incompleteCacheRefs.isEmpty()) {
synchronized (incompleteCacheRefs) {
incompleteCacheRefs.removeIf(x -> x.resolveCacheRef() != null);
}
}
/**
* 重新解析存放在 {@link #incompleteStatements} 中的 {@link XMLStatementBuilder} 实例。
* 将重新解析成功XMLStatementBuilder实例移除
*/
if (!incompleteStatements.isEmpty()) {
synchronized (incompleteStatements) {
incompleteStatements.removeIf(x -> {
x.parseStatementNode();
return true;
});
}
}
/**
* 重新解析存放在 {@link #incompleteMethods} 中的 {@link MethodResolver} 实例。
* 将重新解析成功MethodResolver实例移除
*/
if (!incompleteMethods.isEmpty()) {
synchronized (incompleteMethods) {
incompleteMethods.removeIf(x -> {
x.resolve();
return true;
});
}
}
}
/**
* 重新解析存放在 {@link #incompleteResultMaps} 中的 {@link ResultMapResolver} 实例。
* 还是解析失败,就会抛出异常。
*/
private void parsePendingResultMaps() {
if (incompleteResultMaps.isEmpty()) {
return;
}
synchronized (incompleteResultMaps) {
boolean resolved;
IncompleteElementException ex = null;
/**
* 该循环会在只要incompleteResultMaps里面所有ResultMapResolver实例有一个
* 调用resolve()不成功抛出异常都会终止循环。
* 不用担心incompleteResultMaps里面所有ResultMapResolver实例调用resolve()都成功会出现死循环,
* 因为每次resolve成功都会从incompleteResultMaps中移除
*/
do {
resolved = false;
/**
* 遍历incompleteResultMaps里面的ResultMapResolver实例,重新调用
* ResultMapResolver实例的resolve()方法
*/
Iterator iterator = incompleteResultMaps.iterator();
while (iterator.hasNext()) {
try {
//构建{@link ResultMap}实例,并添加到{@link org.apache.ibatis.session.Configuration}
iterator.next().resolve();
//到这来证明resolve已经执行成功,就会从incompleteResultMaps中移除
iterator.remove();
resolved = true;
} catch (IncompleteElementException e) {
ex = e;
}
}
} while (resolved);
//经过上面的循环incompleteResultMaps还是有ResultMapResolver实例,抛出异常也是合理的。
if (!incompleteResultMaps.isEmpty() && ex != null) {
// At least one result map is unresolvable.至少有一个ResultMap实例是无法解决的。
throw ex;
}
}
}
/**
* Extracts namespace from fully qualified statement id.
*
* @param statementId
* @return namespace or null when id does not contain period.
*/
protected String extractNamespace(String statementId) {
int lastPeriod = statementId.lastIndexOf('.');
return lastPeriod > 0 ? statementId.substring(0, lastPeriod) : null;
}
// Slow but a one time cost. A better solution is welcome.
protected void checkGloballyForDiscriminatedNestedResultMaps(ResultMap rm) {
if (rm.hasNestedResultMaps()) {
for (Map.Entry entry : resultMaps.entrySet()) {
Object value = entry.getValue();
if (value instanceof ResultMap) {
ResultMap entryResultMap = (ResultMap) value;
if (!entryResultMap.hasNestedResultMaps() && entryResultMap.getDiscriminator() != null) {
Collection discriminatedResultMapNames = entryResultMap.getDiscriminator().getDiscriminatorMap().values();
if (discriminatedResultMapNames.contains(rm.getId())) {
entryResultMap.forceNestedResultMaps();
}
}
}
}
}
}
// Slow but a one time cost. A better solution is welcome.
protected void checkLocallyForDiscriminatedNestedResultMaps(ResultMap rm) {
if (!rm.hasNestedResultMaps() && rm.getDiscriminator() != null) {
for (Map.Entry entry : rm.getDiscriminator().getDiscriminatorMap().entrySet()) {
String discriminatedResultMapName = entry.getValue();
if (hasResultMap(discriminatedResultMapName)) {
ResultMap discriminatedResultMap = resultMaps.get(discriminatedResultMapName);
if (discriminatedResultMap.hasNestedResultMaps()) {
rm.forceNestedResultMaps();
break;
}
}
}
}
}
/**
* 继承HashMap,并重写put方法使得当有相同key传进StrictMap的时候,能抛出异常,并对key的值前缀有'.'的,进行以'.'后面的字符串为key写入strictMap
* 重新get使得找不到key对应的value时抛出异常,或者对获取出来的value属于Ambiguity类的抛出异常
* @param
*/
protected static class StrictMap extends HashMap {
private static final long serialVersionUID = -4950446264854982944L;
private final String name;
/**
* 冲突消息生成方,BiFunction:Java8的函数式编程
*/
private BiFunction conflictMessageProducer;
public StrictMap(String name, int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
this.name = name;
}
public StrictMap(String name, int initialCapacity) {
super(initialCapacity);
this.name = name;
}
public StrictMap(String name) {
super();
this.name = name;
}
public StrictMap(String name, Map m) {
super(m);
this.name = name;
}
/**
* Assign a function for producing a conflict error message when contains value with the same key.
*
* function arguments are 1st is saved value and 2nd is target value.
* @param conflictMessageProducer A function for producing a conflict error message
* @return a conflict error message
* @since 3.5.0
*/
public StrictMap conflictMessageProducer(BiFunction conflictMessageProducer) {
this.conflictMessageProducer = conflictMessageProducer;
return this;
}
/**
* 重写put方法,如果key在已经在StrictMap中找到了,就会抛出异常,
* 如果key是以'.'作为前缀,那么取'.'后面的字符串作为key,当这个key存在在strictMap中时,会用new一个Ambiguity包装shortKey存进strictMap中,
* 赋值就很正常的将这个key和参数value存进strictMap中
*/
@Override
@SuppressWarnings("unchecked")
public V put(String key, V value) {
if (containsKey(key)) {
throw new IllegalArgumentException(name + " already contains value for " + key
+ (conflictMessageProducer == null ? "" : conflictMessageProducer.apply(super.get(key), value)));
}
if (key.contains(".")) {
final String shortKey = getShortName(key);
if (super.get(shortKey) == null) {
super.put(shortKey, value);
} else {
super.put(shortKey, (V) new Ambiguity(shortKey));
}
}
return super.put(key, value);
}
/**
* 重写了get方法,获取不了value的时候或者value是Ambiguity类的时候抛出IllegalArgumentException,
* 这里其实我也不是很理解为啥put方法的时候value属于Ambiguity时候抛出异常,而是要在get时候才抛出,还要为啥要用Ambiguity类来封装。
* 我只能推测原因是因为.XXX的key属于一种测试或者保留的数据,所以才让开发人员在获取的时候才抛出异常。
*/
@Override
public V get(Object key) {
V value = super.get(key);
if (value == null) {
throw new IllegalArgumentException(name + " does not contain value for " + key);
}
if (value instanceof Ambiguity) {
throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name
+ " (try using the full name including the namespace, or rename one of the entries)");
}
return value;
}
protected static class Ambiguity {
final private String subject;
public Ambiguity(String subject) {
this.subject = subject;
}
public String getSubject() {
return subject;
}
}
/**
* 获取缩写
*/
private String getShortName(String key) {
final String[] keyParts = key.split("\\.");
return keyParts[keyParts.length - 1];
}
}
}