Mybatis源码解读系列(二)-Configuration的成员变量介绍

一、成员变量

​ 首先我们来看下Configuration的一些成员变量

1、简单参数

public class Configuration {
   

  protected Environment environment;

  protected boolean safeRowBoundsEnabled;
  protected boolean safeResultHandlerEnabled = true;
  protected boolean mapUnderscoreToCamelCase;    
  protected boolean aggressiveLazyLoading;
  protected boolean multipleResultSetsEnabled = true;
  protected boolean useGeneratedKeys;
  protected boolean useColumnLabel = true;
  protected boolean cacheEnabled = true;
  protected boolean callSettersOnNulls;
  protected boolean useActualParamName = true;
  ......

这些节点是我们可以在mybatis的配置文件配置,然后mybatis就会将这些信息读取到这个Configuration中来,我们们主要梳理下一些重要的属性。

2、defaultStatementTimeout

protected Integer defaultStatementTimeout;

​ 这个就是设置Statement在进行查询连接的时候的默认超时时间

3、defaultFetchSize [setting name=“defaultFetchSize” value=“100”]

protected Integer defaultFetchSize;

​ 这个就是用来设置fetchSize的值的,这个对于数据库来说,就是它不会将你能查询出来的一次全部返还回来,而是一次返回defaultFetchSize设置的值,当这个一直往后移完了,其再将后面下一批数据再返回,这样就能避免OOM的情况。

4、defaultResultSetType

protected ResultSetType defaultResultSetType;

这个参数就是用来设置再ResultSet遍历获取结果的时候类型的滚动情况

public enum ResultSetType {
   
  
  DEFAULT(-1),
  FORWARD_ONLY(ResultSet.TYPE_FORWARD_ONLY),
  SCROLL_INSENSITIVE(ResultSet.TYPE_SCROLL_INSENSITIVE),
  SCROLL_SENSITIVE(ResultSet.TYPE_SCROLL_SENSITIVE);

​ 这里的FORWARD_ONLY表示只能往前、SCROLL_INSENSITIVE能左右,但其对数据库的修改不敏感、SCROLL_SENSITIVE对数据库的修改是敏感的。

5、defaultExecutorType

protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
public enum ExecutorType {
   
  SIMPLE, REUSE, BATCH
}

​ 这个是mybatis的执行器类型,可以看到其有三种:SIMPLE是简单的执行器、REUSE是可复用的执行器(指定是其会将Statement缓存起来重复利用,而不是直接关闭它)、BATCH这个是批处理的执行器。

6、autoMappingBehavior

protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;

​ 其总共有3种类型:

public enum AutoMappingBehavior {
   
  NONE,
  PARTIAL,
  FULL
}

​ NONO表示不进行自动映射,PARTIAL表示中对没有嵌套的属性进行自动映射,FULL表示其他的或者嵌套的都进行映射。

它这里要表示的其实是:

public class User {
   

  private Integer id;
  private String name;
  private Long phone; // phone number of Long type

  private List<Pet> pets;
insert into users (id, name, phone, phone_number) values(1, 'User1', '+86 12345678901', 12345678901);
<select id="getUserWithPhoneNumber" resultMap="resultWithPhoneNumber">
    select * from users where id = #{
   id}
</select>

<resultMap type="org.apache.ibatis.submitted.automapping.User" id="resultWithPhoneNumber">
    <result property="phone" column="phone_number"/>
</resultMap>
<select id="getUser" resultMap="result">
    select id, name from users where id = #{
   id}
</select>

<resultMap type="org.apache.ibatis.submitted.automapping.User" id="result">
</resultMap>

例如这个设置类型为PARTIAL(默认),用getUser进行查询,其在resultMap没有写内容,同时由于”Long phone”与数据看中的”phone”类型不同其是字符,所以不会进行匹配,这个时候用getUserWithPhoneNumber其result有设置对应的映射,所以能查询出来。对于pets这个嵌套,就算是用sql查询出来了对应的关系,其也不会设置对应,所以这个时候需要设置FULL,当需要注意这个是全局设置,但其实还是可以设置sql语句级别:

private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
   
  if (resultMap.getAutoMapping() != null) {
   
    return resultMap.getAutoMapping();
  } else {
   
    if (isNested) {
   
      return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior();
    } else {
   
      return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();
    }
  }
}

​ 可以看到这里首先是看autoMapping属性:

<resultMap type="org.apache.ibatis.submitted.automapping.User" id="resultWithPhoneNumber" autoMapping="true">
    <result property="phone" column="phone_number"/>
</resultMap>

7、variables

protected Properties variables = new Properties();

​ 这个在mybatis文件中设置读取的properties的信息,例如

<properties>
<property name="driver" value="xxx" />
<property name="url" value="xxx" />
<property name="username" value="xxx" />
<property name="password" value="xxx" />
</properties>

8、objectFactory

protected ObjectFactory objectFactory = new DefaultObjectFactory();
public interface ObjectFactory {
   
  void setProperties(Properties properties);
  <T> T create(Class<T> type);
  <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
  <T> boolean isCollection(Class<T> type);
}
这个是用来产生对象的工厂的,我们可以看其接口,主要有两个方法,一个是主键创建,另一个是通过构造方法&参数来创建对象。

9、objectWrapperFactory

protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
这个类是用来产生包装对象的,这个工厂是用来生产ObjectWrapper的。
public interface ObjectWrapper {
   
  ......
  String[] getGetterNames();
  String[] getSetterNames();
  Class<?> getSetterType(String name);
  Class<?> getGetterType(String name);
  boolean hasSetter(String name);
  boolean hasGetter(String name);
  ......
}

例如用来判断有没有这个属性的get|set方法。

10、mapperRegistry

protected MapperRegistry mapperRegistry = new MapperRegistry(this);
public class MapperRegistry {
   

  private Configuration config;
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
    ......

这个类就是用来存放Mapper接口类以及这个接口类所对应的代理工厂。

11、interceptorChain

protected final InterceptorChain interceptorChain = new InterceptorChain();
public class InterceptorChain {
   
  private final List<Interceptor> interceptors = new ArrayList<Interceptor>();

这个类就是用来存放Mybatis的Interceptor的。

12、typeHandlerRegistry

protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();

这个我们上一篇也有提到,是用来做类型处理的,将对应表示类型的字符,来获取对应字符表示的类型或类型处理器。

13、typeAliasRegistry

protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();

这个是用来处理别名的,例如直接设置类的别名,或者自动扫描包名,使用的时候只需要些对应的类名称就可以了:

<typeAliases>
   <typeAlias type="org.apache.ibatis.submitted.cache.Person" alias="Person" /> 
</typeAliases>
<typeAliases>
    <package name="org.apache.ibatis.submitted.permissions" />
</typeAliases>

14、languageRegistry

protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();

这个在上一篇也有梳理过,其主要是用来驱动对sql脚本的解析的。

15、mappedStatements

protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");

这个Map是很重要的,其就是对应Mapper接口的方法为key,对应的MappedStatement包含这个接口方法正常执行sql所需要的一些数据。

在这里插入图片描述

不过我们可以看到这些key有些带了包名有些没有带包名,之后我们梳理流程的时候看为什么会这样。

在这里插入图片描述

 但我们看MappedStatement的对应属性。

​ 1)、resource

​ 这个表示资源所在位置。

​ 2)、id

​ 这个就是唯一表示,可以看到前面的key没有包名,这个也是带包名的,同时通过这两个key我们也能大致知道为什么mybatis为什么是不支持方法同名的(方法对应的参数类型不同),因为一是方法名确认,而没有参数表示的。

​ 3)、statementType

public enum StatementType {
   
  STATEMENT, PREPARED, CALLABLE
}

​ 这个就是表示一个sql的Statement类型:STATEMENT就是直接表示的简单的Statement、PREPARED表示的是PreparedStatement、CALLABLE表示的与存储过程调用相关的,我们就先忽略,这里的区别就是获取不同的Statement处理器:

public 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());
  }

}

​ 4)、resultSetType

private ResultSetType resultSetType;

​ 结果集类型,这个在上面有对应介绍

​ 5)、sqlSource

private SqlSource sqlSource;

​ 这个在上篇文章有过对应介绍,表示处理与Sql节本相关的内容的。

​ 6)、parameterMap

private ParameterMap parameterMap;
<parameterMap id="selectAuthor" type="org.apache.ibatis.domain.blog.Author">
   <parameter property="id" resultMap="id"/>
</parameterMap>

​ 这个表示参数的map映射

​ 7)、resultMaps

private List<ResultMap> resultMaps;
 id="personMap2" type="Person">
    <id property="id" column="id"/>
    <result property="firstName" column="firstName"/>

​ 这个就是表示对应的返回映射,这里可以看到其是一个数组,但一般是只有一个值。这里看注释之所以是数组是因为一些存储过程可能会有两个返回。

​ 8)、sqlCommandType

public enum SqlCommandType {
   
  UNKNOWN, INSERT, UPDATE, DELETE, SELECT;
}

​ 这个就是对应的哪种操作。

​ 9)、keyColumns&keyProperties&keyGenerator

private String[] keyColumns;
private String[] keyProperties;
private KeyGenerator keyGenerator;

​ 这个是用于主键策略的,我们跳过。

​ 10)、hasNestedResultMaps

private boolean hasNestedResultMaps;

​ 这个表示是否有嵌套ResultMap。

​ 11)、databaseId

private String databaseId;

​ 这个表示这条sql使用的数据库Id。

<databaseIdProvider type="DB_VENDOR">
   <property name="SQL Server" value="sqlserver"/>
   <property name="DB2" value="db2"/>
   <property name="Oracle" value="oracle" />
   <property name="HSQL Database Engine" value="hsql" />
</databaseIdProvider>
<select id="select1" databaseId="hsql" resultType="string" parameterType="int">
   select name from hsql where
   id=#{
   value}
</select>

​ 12)、resultSets

<select id="getNamesAndItemsLinked" statementType="CALLABLE" resultSets="names,items" resultMap="nameResultLinked">
  {
   call sptest.getnamesanditems()}
</select>
create procedure sptest.getnamesanditems()
modifies sql data
dynamic result sets 2
BEGIN ATOMIC
  declare cur1 cursor for select * from sptest.names;
  declare cur2 cursor for select * from sptest.items;
  open cur1;
  open cur2;
END
go

​ 这个是存储过程可能有两个返回结果集。现在还没有在工作中用到这种用法,不是很了解,先不具体分析了。

​ 13)、resultMaps

protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>("Result Maps collection");

​ 这个是整个加载的结果映射集

在这里插入图片描述

​ 14)、parameterMaps

protected final Map<String, ParameterMap> parameterMaps = new StrictMap<ParameterMap>("Parameter Maps collection");

​ 与上面类似,这个是总的参数映射集。

15)、sqlFragments

protected final Map<String, XNode> sqlFragments = new StrictMap<XNode>("XML fragments parsed from previous mappers");

​ 这个是存放sql片段节点的。

​ 16)、incompleteStatements&incompleteCacheRefs&incompleteResultMaps&incompleteMethods

protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<XMLStatementBuilder>();
protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<CacheRefResolver>();
protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<ResultMapResolver>();
protected final Collection<MethodResolver> incompleteMethods = new LinkedList<MethodResolver>();

​ 这些是用来存放一些例如你的sql标记写错了,这个就是用来收集的。

} catch (IncompleteElementException e) {
   
  configuration.addIncompleteStatement(statementParser);
}

​ 例如这几个字段的使用一般是放在catch中记录的,

张贴在2