自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MyBatis配置解析過程,你學(xué)會(huì)了嗎?

開發(fā) 前端
在configuration節(jié)點(diǎn)之下,我們可以配置10個(gè)子節(jié)點(diǎn), 分別為:properties、typeAliases、plugins、objectFactory、objectWrapperFactory、settings、environments、databaseIdProvider、typeHandlers、mappers。

配置解析主體方法

public Configuration parse() {  
    if (parsed) {  
        throw new BuilderException("Each XMLConfigBuilder can only be used once.");  
    }  
    parsed = true;  
    //源碼中沒有這一句,只有 parseConfiguration(parser.evalNode("/configuration"));  
    //為了讓讀者看得更明晰,源碼拆分為以下兩句  
    XNode configurationNode = parser.evalNode("/configuration");  
    parseConfiguration(configurationNode);  
    return configuration;  
}  
/** 
 * 解析 "/configuration"節(jié)點(diǎn)下的子節(jié)點(diǎn)信息,然后將解析的結(jié)果設(shè)置到Configuration對象中 
 */  
private void parseConfiguration(XNode root) {  
    try {  
        //1.首先處理properties 節(jié)點(diǎn)     
        propertiesElement(root.evalNode("properties")); //issue #117 read properties first  
        //2.處理typeAliases  
        typeAliasesElement(root.evalNode("typeAliases"));  
        //3.處理插件  
        pluginElement(root.evalNode("plugins"));  
        //4.處理objectFactory  
        objectFactoryElement(root.evalNode("objectFactory"));  
        //5.objectWrapperFactory  
        objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));  
        //6.settings  
        settingsElement(root.evalNode("settings"));  
        //7.處理environments  
        environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631  
        //8.database  
        databaseIdProviderElement(root.evalNode("databaseIdProvider"));  
        //9.typeHandlers  
        typeHandlerElement(root.evalNode("typeHandlers"));  
        //10.mappers  
        mapperElement(root.evalNode("mappers"));  
    } catch (Exception e) {  
        throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);  
    }  
}

通過以上源碼,就能看出,在mybatis的配置文件中:

  • configuration節(jié)點(diǎn)為根節(jié)點(diǎn)。
  • 在configuration節(jié)點(diǎn)之下,我們可以配置10個(gè)子節(jié)點(diǎn), 分別為:properties、typeAliases、plugins、objectFactory、objectWrapperFactory、settings、environments、databaseIdProvider、typeHandlers、mappers。

配置文件元素

properties

<configuration>
    <!-- 方法一: 從外部指定properties配置文件, 除了使用resource屬性指定外,還可通過url屬性指定url  
        <properties resource="dbConfig.properties"></properties> 
    -->
    <!-- 方法二: 直接配置為xml -->
    <properties>
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test1"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </properties>

那么,要是兩種方法都同時(shí)配置了,那么最終會(huì)采用什么樣的配置呢?

  1. 首先會(huì)先檢查文件中的xml配置 和 外部指定的properties(也就是resource),如果兩個(gè)同時(shí)配置了,那么就會(huì)報(bào)異常
  2. 接著會(huì)加載Java Configuration的配置

a.如果有Configuration的配置,那么最終會(huì)使用Configuration的配置

b.如果沒有Configuration的配置,那么最終會(huì)使用上一步的xml的配置或resource配置

這是因?yàn)榕渲檬谴娣旁赑roperties,它繼承自HashTable類,當(dāng)依次將上述幾種配置源put進(jìn)去時(shí),后加載的配置會(huì)覆蓋先加載的配置。所以,最終應(yīng)用配置時(shí)Configuration配置優(yōu)先級最高,其次是另外兩種中的一種。具體可以參考接下來的源碼分析。

envirements

<environments default="development">
    <environment id="development">
        <!-- 
        JDBC–這個(gè)配置直接簡單使用了JDBC的提交和回滾設(shè)置。它依賴于從數(shù)據(jù)源得到的連接來管理事務(wù)范圍。
        MANAGED–這個(gè)配置幾乎沒做什么。它從來不提交或回滾一個(gè)連接。而它會(huì)讓容器來管理事務(wù)的整個(gè)生命周期(比如Spring或JEE應(yīng)用服務(wù)器的上下文)。
        -->
        <transactionManager type="JDBC"/>
        <!--
        UNPOOLED–這個(gè)數(shù)據(jù)源的實(shí)現(xiàn)是每次被請求時(shí)簡單打開和關(guān)閉連接
        POOLED–mybatis實(shí)現(xiàn)的簡單的數(shù)據(jù)庫連接池類型,它使得數(shù)據(jù)庫連接可被復(fù)用,不必在每次請求時(shí)都去創(chuàng)建一個(gè)物理的連接。
        JNDI – 通過jndi從tomcat之類的容器里獲取數(shù)據(jù)源。
        -->
        <dataSource type="POOLED">
            <!--
            如果上面沒有指定數(shù)據(jù)庫配置的properties文件,那么此處可以這樣直接配置 
            <property name="driver" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/test1"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
            -->
         
            <!-- 上面指定了數(shù)據(jù)庫配置文件, 配置文件里面也是對應(yīng)的這四個(gè)屬性 -->
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>  
        </dataSource>
    </environment>
    
    <!-- 我再指定一個(gè)environment -->
    <environment id="test">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="com.mysql.jdbc.Driver"/>
            <!-- 與上面的url不一樣 -->
            <property name="url" value="jdbc:mysql://localhost:3306/demo"/>
            <property name="username" value="root"/>
            <property name="password" value="root"/>
        </dataSource>
    </environment>
</environments>

environments元素節(jié)點(diǎn)可以配置多個(gè)environment子節(jié)點(diǎn), 怎么理解呢?

假如我們系統(tǒng)的開發(fā)環(huán)境和正式環(huán)境所用的數(shù)據(jù)庫不一樣(這是肯定的), 那么可以設(shè)置兩個(gè)environment, 兩個(gè)id分別對應(yīng)開發(fā)環(huán)境(dev)和正式環(huán)境(final),那么通過配置environments的default屬性就能選擇對應(yīng)的environment了, 例如,我將environments的deault屬性的值配置為dev, 那么就會(huì)選擇dev的environment。 那么這個(gè)是怎么實(shí)現(xiàn)的呢?

看源碼: mybatis 是通過XMLConfigBuilder這個(gè)類在解析mybatis配置文件的,XMLConfigBuilder對于environments的解析:

public class XMLConfigBuilder extends BaseBuilder {

    private boolean parsed;
    // xml解析器
    private XPathParser parser;
    private String environment;
  
    
    // 看看解析enviroments元素節(jié)點(diǎn)的方法
    private void environmentsElement(XNode context) throws Exception {
        if (context != null) {
            if (environment == null) {
                //解析environments節(jié)點(diǎn)的default屬性的值
                //例如: <environments default="development">
                environment = context.getStringAttribute("default");
            }
            //遞歸解析environments子節(jié)點(diǎn)
            for (XNode child : context.getChildren()) {
                //<environment id="development">, 只有enviroment節(jié)點(diǎn)有id屬性,那么這個(gè)屬性有何作用?
                //environments 節(jié)點(diǎn)下可以擁有多個(gè) environment子節(jié)點(diǎn)
                //類似于這樣: <environments default="development"><environment id="development">...</environment><environment id="test">...</environments>
                //意思就是可以對應(yīng)多個(gè)環(huán)境,比如開發(fā)環(huán)境,測試環(huán)境等, 由environments的default屬性去選擇對應(yīng)的enviroment
                String id = child.getStringAttribute("id");
                //isSpecial就是根據(jù)由environments的default屬性去選擇對應(yīng)的enviroment
                if (isSpecifiedEnvironment(id)) {
                    //事務(wù), mybatis有兩種:JDBC 和 MANAGED, 配置為JDBC則直接使用JDBC的事務(wù),配置為MANAGED則是將事務(wù)托管給容器, 
                    TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
                    //enviroment節(jié)點(diǎn)下面就是dataSource節(jié)點(diǎn)了,解析dataSource節(jié)點(diǎn)(下面會(huì)貼出解析dataSource的具體方法)
                    DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
                    DataSource dataSource = dsFactory.getDataSource();
                    Environment.Builder environmentBuilder = new Environment.Builder(id)
                          .transactionFactory(txFactory)
                          .dataSource(dataSource);
                    //將dataSource設(shè)置進(jìn)configuration對象
                    configuration.setEnvironment(environmentBuilder.build());
                }
            }
        }
    }
    
    //dataSource的解析方法
    private DataSourceFactory dataSourceElement(XNode context) throws Exception {
        if (context != null) {
            //dataSource的連接池
            String type = context.getStringAttribute("type");
            //子節(jié)點(diǎn) name, value屬性set進(jìn)一個(gè)properties對象
            Properties props = context.getChildrenAsProperties();
            //創(chuàng)建dataSourceFactory
            DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
            factory.setProperties(props);
            return factory;
        }
        throw new BuilderException("Environment declaration requires a DataSourceFactory.");
    } 
}

還有一個(gè)問題, 在配置dataSource的時(shí)候使用了 ${driver} 這種表達(dá)式, 那么這種形式是怎么解析的?其實(shí),是通過PropertyParser這個(gè)類解析:

/**
 * 這個(gè)類解析${}這種形式的表達(dá)式
 */
public class PropertyParser {

    public static String parse(String string, Properties variables) {
        VariableTokenHandler handler = new VariableTokenHandler(variables);
        GenericTokenParser parser = new GenericTokenParser("${", "}", handler);
        return parser.parse(string);
    }

    private static class VariableTokenHandler implements TokenHandler {
        private Properties variables;

        public VariableTokenHandler(Properties variables) {
            this.variables = variables;
        }

        public String handleToken(String content) {
            if (variables != null && variables.containsKey(content)) {
                return variables.getProperty(content);
            }
            return "${" + content + "}";
        }
    }
}

以上就是對于properties 和 environments元素節(jié)點(diǎn)的分析,比較重要的都在對于源碼的注釋中標(biāo)出。

typeAliases

typeAliases節(jié)點(diǎn)主要用來設(shè)置別名,其實(shí)這是挺好用的一個(gè)功能, 通過配置別名,我們不用再指定完整的包名,并且還能取別名。

例如: 我們在使用 com.demo.entity. UserEntity 的時(shí)候,我們可以直接配置一個(gè)別名user, 這樣以后在配置文件中要使用到com.demo.entity.UserEntity的時(shí)候,直接使用User即可。

就以上例為例,我們來實(shí)現(xiàn)一下,看看typeAliases的配置方法:

<configuration>
    <typeAliases>
        <!--
        通過package, 可以直接指定package的名字, mybatis會(huì)自動(dòng)掃描你指定包下面的javabean,
        并且默認(rèn)設(shè)置一個(gè)別名,默認(rèn)的名字為: javabean 的首字母小寫的非限定類名來作為它的別名。
        也可在javabean 加上注解@Alias 來自定義別名, 例如: @Alias(user) 
        <package name="com.dy.entity"/>
        -->
        <typeAlias alias="UserEntity" type="com.dy.entity.User"/>
    </typeAliases>
  
    ......
  
</configuration>

再寫一段測試代碼,看看有沒生效:(我只寫一段偽代碼)

Configuration con = sqlSessionFactory.getConfiguration();
Map<String, Class<?>> typeMap = con.getTypeAliasRegistry().getTypeAliases();
for(Entry<String, Class<?>> entry: typeMap.entrySet()) {
    System.out.println(entry.getKey() + " ================> " + entry.getValue().getSimpleName());
}

typeAliasesElement:

/**
 * 解析typeAliases節(jié)點(diǎn)
 */
private void typeAliasesElement(XNode parent) {
    if (parent != null) {
        for (XNode child : parent.getChildren()) {
            //如果子節(jié)點(diǎn)是package, 那么就獲取package節(jié)點(diǎn)的name屬性, mybatis會(huì)掃描指定的package
            if ("package".equals(child.getName())) {
                String typeAliasPackage = child.getStringAttribute("name");
                //TypeAliasRegistry 負(fù)責(zé)管理別名, 這兒就是通過TypeAliasRegistry 進(jìn)行別名注冊, 下面就會(huì)看看TypeAliasRegistry源碼
                configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
            } else {
                //如果子節(jié)點(diǎn)是typeAlias節(jié)點(diǎn),那么就獲取alias屬性和type的屬性值
                String alias = child.getStringAttribute("alias");
                String type = child.getStringAttribute("type");
                try {
                    Class<?> clazz = Resources.classForName(type);
                    if (alias == null) {
                        typeAliasRegistry.registerAlias(clazz);
                    } else {
                        typeAliasRegistry.registerAlias(alias, clazz);
                    }
                } catch (ClassNotFoundException e) {
                    throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
                }
            }
        }
    }
}

重要的源碼在這兒:TypeAliasRegistry.java

public class TypeAliasRegistry {
  
  //這就是核心所在啊, 原來別名就僅僅通過一個(gè)HashMap來實(shí)現(xiàn), key為別名, value就是別名對應(yīng)的類型(class對象)
  private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();

  /**
   * 以下就是mybatis默認(rèn)為我們注冊的別名
   */
  public TypeAliasRegistry() {
    registerAlias("string", String.class);

    registerAlias("byte", Byte.class);
    registerAlias("long", Long.class);
    registerAlias("short", Short.class);
    registerAlias("int", Integer.class);
    registerAlias("integer", Integer.class);
    registerAlias("double", Double.class);
    registerAlias("float", Float.class);
    registerAlias("boolean", Boolean.class);

    registerAlias("byte[]", Byte[].class);
    registerAlias("long[]", Long[].class);
    registerAlias("short[]", Short[].class);
    registerAlias("int[]", Integer[].class);
    registerAlias("integer[]", Integer[].class);
    registerAlias("double[]", Double[].class);
    registerAlias("float[]", Float[].class);
    registerAlias("boolean[]", Boolean[].class);

    registerAlias("_byte", byte.class);
    registerAlias("_long", long.class);
    registerAlias("_short", short.class);
    registerAlias("_int", int.class);
    registerAlias("_integer", int.class);
    registerAlias("_double", double.class);
    registerAlias("_float", float.class);
    registerAlias("_boolean", boolean.class);

    registerAlias("_byte[]", byte[].class);
    registerAlias("_long[]", long[].class);
    registerAlias("_short[]", short[].class);
    registerAlias("_int[]", int[].class);
    registerAlias("_integer[]", int[].class);
    registerAlias("_double[]", double[].class);
    registerAlias("_float[]", float[].class);
    registerAlias("_boolean[]", boolean[].class);

    registerAlias("date", Date.class);
    registerAlias("decimal", BigDecimal.class);
    registerAlias("bigdecimal", BigDecimal.class);
    registerAlias("biginteger", BigInteger.class);
    registerAlias("object", Object.class);

    registerAlias("date[]", Date[].class);
    registerAlias("decimal[]", BigDecimal[].class);
    registerAlias("bigdecimal[]", BigDecimal[].class);
    registerAlias("biginteger[]", BigInteger[].class);
    registerAlias("object[]", Object[].class);

    registerAlias("map", Map.class);
    registerAlias("hashmap", HashMap.class);
    registerAlias("list", List.class);
    registerAlias("arraylist", ArrayList.class);
    registerAlias("collection", Collection.class);
    registerAlias("iterator", Iterator.class);

    registerAlias("ResultSet", ResultSet.class);
  }

  
  /**
   * 處理別名, 直接從保存有別名的hashMap中取出即可
   */
  @SuppressWarnings("unchecked")
  public <T> Class<T> resolveAlias(String string) {
    try {
      if (string == null) return null;
      String key = string.toLowerCase(Locale.ENGLISH); // issue #748
      Class<T> value;
      if (TYPE_ALIASES.containsKey(key)) {
        value = (Class<T>) TYPE_ALIASES.get(key);
      } else {
        value = (Class<T>) Resources.classForName(string);
      }
      return value;
    } catch (ClassNotFoundException e) {
      throw new TypeException("Could not resolve type alias '" + string + "'.  Cause: " + e, e);
    }
  }
  
  /**
   * 配置文件中配置為package的時(shí)候, 會(huì)調(diào)用此方法,根據(jù)配置的報(bào)名去掃描javabean ,然后自動(dòng)注冊別名
   * 默認(rèn)會(huì)使用 Bean 的首字母小寫的非限定類名來作為它的別名
   * 也可在javabean 加上注解@Alias 來自定義別名, 例如: @Alias(user)
   */
  public void registerAliases(String packageName){
    registerAliases(packageName, Object.class);
  }

  public void registerAliases(String packageName, Class<?> superType){
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
    resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
    Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
    for(Class<?> type : typeSet){
      // Ignore inner classes and interfaces (including package-info.java)
      // Skip also inner classes. See issue #6
      if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
        registerAlias(type);
      }
    }
  }

  public void registerAlias(Class<?> type) {
    String alias = type.getSimpleName();
    Alias aliasAnnotation = type.getAnnotation(Alias.class);
    if (aliasAnnotation != null) {
      alias = aliasAnnotation.value();
    } 
    registerAlias(alias, type);
  }

  //這就是注冊別名的本質(zhì)方法, 其實(shí)就是向保存別名的hashMap新增值而已, 呵呵, 別名的實(shí)現(xiàn)太簡單了,對吧
  public void registerAlias(String alias, Class<?> value) {
    if (alias == null) throw new TypeException("The parameter alias cannot be null");
    String key = alias.toLowerCase(Locale.ENGLISH); // issue #748
    if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
      throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");
    }
    TYPE_ALIASES.put(key, value);
  }

  public void registerAlias(String alias, String value) {
    try {
      registerAlias(alias, Resources.classForName(value));
    } catch (ClassNotFoundException e) {
      throw new TypeException("Error registering type alias "+alias+" for "+value+". Cause: " + e, e);
    }
  }
  
  /**
   * 獲取保存別名的HashMap, Configuration對象持有對TypeAliasRegistry的引用,因此,如果需要,我們可以通過Configuration對象獲取
   */
  public Map<String, Class<?>> getTypeAliases() {
    return Collections.unmodifiableMap(TYPE_ALIASES);
  }

}

由源碼可見,設(shè)置別名的原理就這么簡單,Mybatis默認(rèn)給我們設(shè)置了不少別名,在上面代碼中都可以見到。

TypeHandler

Mybatis中的TypeHandler是什么?

無論是 MyBatis 在預(yù)處理語句(PreparedStatement)中設(shè)置一個(gè)參數(shù)時(shí),還是從結(jié)果集中取出一個(gè)值時(shí),都會(huì)用類型處理器將獲取的值以合適的方式轉(zhuǎn)換成 Java 類型。Mybatis默認(rèn)為我們實(shí)現(xiàn)了許多TypeHandler, 當(dāng)我們沒有配置指定TypeHandler時(shí),Mybatis會(huì)根據(jù)參數(shù)或者返回結(jié)果的不同,默認(rèn)為我們選擇合適的TypeHandler處理。

那么,Mybatis為我們實(shí)現(xiàn)了哪些TypeHandler呢? 我們怎么自定義實(shí)現(xiàn)一個(gè)TypeHandler ? 這些都會(huì)在接下來的mybatis的源碼中看到。

先看看配置:

<configuration>
    <typeHandlers>
      <!-- 
          當(dāng)配置package的時(shí)候,mybatis會(huì)去配置的package掃描TypeHandler
          <package name="com.dy.demo"/>
       -->
      
      <!-- handler屬性直接配置我們要指定的TypeHandler -->
      <typeHandler handler=""/>
      
      <!-- javaType 配置java類型,例如String, 如果配上javaType, 那么指定的typeHandler就只作用于指定的類型 -->
      <typeHandler javaType="" handler=""/>
      
      <!-- jdbcType 配置數(shù)據(jù)庫基本數(shù)據(jù)類型,例如varchar, 如果配上jdbcType, 那么指定的typeHandler就只作用于指定的類型  -->
      <typeHandler jdbcType="" handler=""/>
      
      <!-- 也可兩者都配置 -->
      <typeHandler javaType="" jdbcType="" handler=""/>
      
  </typeHandlers>
  
  ......
  
</configuration>

typeHandlerElement

老規(guī)矩,先從對xml的解析講起。

/**
 * 解析typeHandlers節(jié)點(diǎn)
 */
private void typeHandlerElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        //子節(jié)點(diǎn)為package時(shí),獲取其name屬性的值,然后自動(dòng)掃描package下的自定義typeHandler
        if ("package".equals(child.getName())) {
          String typeHandlerPackage = child.getStringAttribute("name");
          typeHandlerRegistry.register(typeHandlerPackage);
        } else {
          //子節(jié)點(diǎn)為typeHandler時(shí), 可以指定javaType屬性, 也可以指定jdbcType, 也可兩者都指定
          //javaType 是指定java類型
          //jdbcType 是指定jdbc類型(數(shù)據(jù)庫類型: 如varchar)
          String javaTypeName = child.getStringAttribute("javaType");
          String jdbcTypeName = child.getStringAttribute("jdbcType");
          //handler就是我們配置的typeHandler
          String handlerTypeName = child.getStringAttribute("handler");
          //resolveClass方法就是我們上篇文章所講的TypeAliasRegistry里面處理別名的方法
          Class<?> javaTypeClass = resolveClass(javaTypeName);
          //JdbcType是一個(gè)枚舉類型,resolveJdbcType方法是在獲取枚舉類型的值
          JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
          Class<?> typeHandlerClass = resolveClass(handlerTypeName);
          //注冊typeHandler, typeHandler通過TypeHandlerRegistry這個(gè)類管理
          if (javaTypeClass != null) {
            if (jdbcType == null) {
              typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
            } else {
              typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
            }
          } else {
            typeHandlerRegistry.register(typeHandlerClass);
          }
        }
      }
    }
}

接下來看看TypeHandler的管理注冊類:TypeHandlerRegistry.java

/**
 * typeHandler注冊管理類
 */
public final class TypeHandlerRegistry {

  //源碼一上來,二話不說,幾個(gè)大大的HashMap就出現(xiàn),這不又跟上次講的typeAliases的注冊類似么

  //基本數(shù)據(jù)類型與其包裝類
  private static final Map<Class<?>, Class<?>> reversePrimitiveMap = new HashMap<Class<?>, Class<?>>() {
    private static final long serialVersionUID = 1L;
    {
      put(Byte.class, byte.class);
      put(Short.class, short.class);
      put(Integer.class, int.class);
      put(Long.class, long.class);
      put(Float.class, float.class);
      put(Double.class, double.class);
      put(Boolean.class, boolean.class);
      put(Character.class, char.class);
    }
  };

  //這幾個(gè)MAP不用說就知道存的是什么東西吧,命名的好處
  private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class);
  private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>();
  private final TypeHandler<Object> UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this);
  private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<Class<?>, TypeHandler<?>>();

  //就像上篇文章講的typeAliases一樣,mybatis也默認(rèn)給我們注冊了不少的typeHandler
  //具體如下
  public TypeHandlerRegistry() {
    register(Boolean.class, new BooleanTypeHandler());
    register(boolean.class, new BooleanTypeHandler());
    register(JdbcType.BOOLEAN, new BooleanTypeHandler());
    register(JdbcType.BIT, new BooleanTypeHandler());

    register(Byte.class, new ByteTypeHandler());
    register(byte.class, new ByteTypeHandler());
    register(JdbcType.TINYINT, new ByteTypeHandler());

    register(Short.class, new ShortTypeHandler());
    register(short.class, new ShortTypeHandler());
    register(JdbcType.SMALLINT, new ShortTypeHandler());

    register(Integer.class, new IntegerTypeHandler());
    register(int.class, new IntegerTypeHandler());
    register(JdbcType.INTEGER, new IntegerTypeHandler());

    register(Long.class, new LongTypeHandler());
    register(long.class, new LongTypeHandler());

    register(Float.class, new FloatTypeHandler());
    register(float.class, new FloatTypeHandler());
    register(JdbcType.FLOAT, new FloatTypeHandler());

    register(Double.class, new DoubleTypeHandler());
    register(double.class, new DoubleTypeHandler());
    register(JdbcType.DOUBLE, new DoubleTypeHandler());

    register(String.class, new StringTypeHandler());
    register(String.class, JdbcType.CHAR, new StringTypeHandler());
    register(String.class, JdbcType.CLOB, new ClobTypeHandler());
    register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
    register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
    register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
    register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
    register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
    register(JdbcType.CHAR, new StringTypeHandler());
    register(JdbcType.VARCHAR, new StringTypeHandler());
    register(JdbcType.CLOB, new ClobTypeHandler());
    register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
    register(JdbcType.NVARCHAR, new NStringTypeHandler());
    register(JdbcType.NCHAR, new NStringTypeHandler());
    register(JdbcType.NCLOB, new NClobTypeHandler());

    register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
    register(JdbcType.ARRAY, new ArrayTypeHandler());

    register(BigInteger.class, new BigIntegerTypeHandler());
    register(JdbcType.BIGINT, new LongTypeHandler());

    register(BigDecimal.class, new BigDecimalTypeHandler());
    register(JdbcType.REAL, new BigDecimalTypeHandler());
    register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
    register(JdbcType.NUMERIC, new BigDecimalTypeHandler());

    register(Byte[].class, new ByteObjectArrayTypeHandler());
    register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
    register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
    register(byte[].class, new ByteArrayTypeHandler());
    register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
    register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
    register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
    register(JdbcType.BLOB, new BlobTypeHandler());

    register(Object.class, UNKNOWN_TYPE_HANDLER);
    register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
    register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);

    register(Date.class, new DateTypeHandler());
    register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
    register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
    register(JdbcType.TIMESTAMP, new DateTypeHandler());
    register(JdbcType.DATE, new DateOnlyTypeHandler());
    register(JdbcType.TIME, new TimeOnlyTypeHandler());

    register(java.sql.Date.class, new SqlDateTypeHandler());
    register(java.sql.Time.class, new SqlTimeTypeHandler());
    register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());

    // issue #273
    register(Character.class, new CharacterTypeHandler());
    register(char.class, new CharacterTypeHandler());
  }

  public boolean hasTypeHandler(Class<?> javaType) {
    return hasTypeHandler(javaType, null);
  }

  public boolean hasTypeHandler(TypeReference<?> javaTypeReference) {
    return hasTypeHandler(javaTypeReference, null);
  }

  public boolean hasTypeHandler(Class<?> javaType, JdbcType jdbcType) {
    return javaType != null && getTypeHandler((Type) javaType, jdbcType) != null;
  }

  public boolean hasTypeHandler(TypeReference<?> javaTypeReference, JdbcType jdbcType) {
    return javaTypeReference != null && getTypeHandler(javaTypeReference, jdbcType) != null;
  }

  public TypeHandler<?> getMappingTypeHandler(Class<? extends TypeHandler<?>> handlerType) {
    return ALL_TYPE_HANDLERS_MAP.get(handlerType);
  }

  public <T> TypeHandler<T> getTypeHandler(Class<T> type) {
    return getTypeHandler((Type) type, null);
  }

  public <T> TypeHandler<T> getTypeHandler(TypeReference<T> javaTypeReference) {
    return getTypeHandler(javaTypeReference, null);
  }

  public TypeHandler<?> getTypeHandler(JdbcType jdbcType) {
    return JDBC_TYPE_HANDLER_MAP.get(jdbcType);
  }

  public <T> TypeHandler<T> getTypeHandler(Class<T> type, JdbcType jdbcType) {
    return getTypeHandler((Type) type, jdbcType);
  }

  public <T> TypeHandler<T> getTypeHandler(TypeReference<T> javaTypeReference, JdbcType jdbcType) {
    return getTypeHandler(javaTypeReference.getRawType(), jdbcType);
  }

  private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) {
    Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = TYPE_HANDLER_MAP.get(type);
    TypeHandler<?> handler = null;
    if (jdbcHandlerMap != null) {
      handler = jdbcHandlerMap.get(jdbcType);
      if (handler == null) {
        handler = jdbcHandlerMap.get(null);
      }
    }
    if (handler == null && type != null && type instanceof Class && Enum.class.isAssignableFrom((Class<?>) type)) {
      handler = new EnumTypeHandler((Class<?>) type);
    }
    @SuppressWarnings("unchecked")
    // type drives generics here
    TypeHandler<T> returned = (TypeHandler<T>) handler;
    return returned;
  }

  public TypeHandler<Object> getUnknownTypeHandler() {
    return UNKNOWN_TYPE_HANDLER;
  }

  public void register(JdbcType jdbcType, TypeHandler<?> handler) {
    JDBC_TYPE_HANDLER_MAP.put(jdbcType, handler);
  }

  //
  // REGISTER INSTANCE
  //

  /**
   * 只配置了typeHandler, 沒有配置jdbcType 或者javaType
   */
  @SuppressWarnings("unchecked")
  public <T> void register(TypeHandler<T> typeHandler) {
    boolean mappedTypeFound = false;
    //在自定義typeHandler的時(shí)候,可以加上注解MappedTypes 去指定關(guān)聯(lián)的javaType
    //因此,此處需要掃描MappedTypes注解
    MappedTypes mappedTypes = typeHandler.getClass().getAnnotation(MappedTypes.class);
    if (mappedTypes != null) {
      for (Class<?> handledType : mappedTypes.value()) {
        register(handledType, typeHandler);
        mappedTypeFound = true;
      }
    }
    // @since 3.1.0 - try to auto-discover the mapped type
    if (!mappedTypeFound && typeHandler instanceof TypeReference) {
      try {
        TypeReference<T> typeReference = (TypeReference<T>) typeHandler;
        register(typeReference.getRawType(), typeHandler);
        mappedTypeFound = true;
      } catch (Throwable t) {
        // maybe users define the TypeReference with a different type and are not assignable, so just ignore it
      }
    }
    if (!mappedTypeFound) {
      register((Class<T>) null, typeHandler);
    }
  }

  /**
   * 配置了typeHandlerhe和javaType
   */
  public <T> void register(Class<T> javaType, TypeHandler<? extends T> typeHandler) {
    register((Type) javaType, typeHandler);
  }

  private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) {
    //掃描注解MappedJdbcTypes
    MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
    if (mappedJdbcTypes != null) {
      for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
        register(javaType, handledJdbcType, typeHandler);
      }
      if (mappedJdbcTypes.includeNullJdbcType()) {
        register(javaType, null, typeHandler);
      }
    } else {
      register(javaType, null, typeHandler);
    }
  }

  public <T> void register(TypeReference<T> javaTypeReference, TypeHandler<? extends T> handler) {
    register(javaTypeReference.getRawType(), handler);
  }

  /**
   * typeHandlerhe、javaType、jdbcType都配置了
   */
  public <T> void register(Class<T> type, JdbcType jdbcType, TypeHandler<? extends T> handler) {
    register((Type) type, jdbcType, handler);
  }

  /**
   * 注冊typeHandler的核心方法
   * 就是向Map新增數(shù)據(jù)而已
   */
  private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
    if (javaType != null) {
      Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(javaType);
      if (map == null) {
        map = new HashMap<JdbcType, TypeHandler<?>>();
        TYPE_HANDLER_MAP.put(javaType, map);
      }
      map.put(jdbcType, handler);
      if (reversePrimitiveMap.containsKey(javaType)) {
        register(reversePrimitiveMap.get(javaType), jdbcType, handler);
      }
    }
    ALL_TYPE_HANDLERS_MAP.put(handler.getClass(), handler);
  }

  //
  // REGISTER CLASS
  //

  // Only handler type

  public void register(Class<?> typeHandlerClass) {
    boolean mappedTypeFound = false;
    MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
    if (mappedTypes != null) {
      for (Class<?> javaTypeClass : mappedTypes.value()) {
        register(javaTypeClass, typeHandlerClass);
        mappedTypeFound = true;
      }
    }
    if (!mappedTypeFound) {
      register(getInstance(null, typeHandlerClass));
    }
  }

  // java type + handler type

  public void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
    register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass));
  }

  // java type + jdbc type + handler type

  public void register(Class<?> javaTypeClass, JdbcType jdbcType, Class<?> typeHandlerClass) {
    register(javaTypeClass, jdbcType, getInstance(javaTypeClass, typeHandlerClass));
  }

  // Construct a handler (used also from Builders)

  @SuppressWarnings("unchecked")
  public <T> TypeHandler<T> getInstance(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
    if (javaTypeClass != null) {
      try {
        Constructor<?> c = typeHandlerClass.getConstructor(Class.class);
        return (TypeHandler<T>) c.newInstance(javaTypeClass);
      } catch (NoSuchMethodException ignored) {
        // ignored
      } catch (Exception e) {
        throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
      }
    }
    try {
      Constructor<?> c = typeHandlerClass.getConstructor();
      return (TypeHandler<T>) c.newInstance();
    } catch (Exception e) {
      throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);
    }
  }

 
  /**
   * 根據(jù)指定的pacakge去掃描自定義的typeHander,然后注冊
   */
  public void register(String packageName) {
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
    resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
    Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
    for (Class<?> type : handlerSet) {
      //Ignore inner classes and interfaces (including package-info.java) and abstract classes
      if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
        register(type);
      }
    }
  }
  
  // get information
  
  /**
   * 通過configuration對象可以獲取已注冊的所有typeHandler
   */
  public Collection<TypeHandler<?>> getTypeHandlers() {
    return Collections.unmodifiableCollection(ALL_TYPE_HANDLERS_MAP.values());
  }
  
}

由源碼可以看到, mybatis為我們實(shí)現(xiàn)了那么多TypeHandler, 隨便打開一個(gè)TypeHandler,看其源碼,都可以看到,它繼承自一個(gè)抽象類:BaseTypeHandler, 那么我們是不是也能通過繼承BaseTypeHandler,從而實(shí)現(xiàn)自定義的TypeHandler ? 答案是肯定的。

演示自定義TypeHandler:

@MappedJdbcTypes(JdbcType.VARCHAR)  
//此處如果不用注解指定jdbcType, 那么,就可以在配置文件中通過"jdbcType"屬性指定, 同理, javaType 也可通過 @MappedTypes指定
public class ExampleTypeHandler extends BaseTypeHandler<String> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
    ps.setString(i, parameter);
  }

  @Override
  public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
    return rs.getString(columnName);
  }

  @Override
  public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    return rs.getString(columnIndex);
  }

  @Override
  public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    return cs.getString(columnIndex);
  }
}

然后,就該配置自定義TypeHandler了:

<configuration>
  <typeHandlers>
      <!-- 由于自定義的TypeHandler在定義時(shí)已經(jīng)通過注解指定了jdbcType, 所以此處不用再配置jdbcType -->
      <typeHandler handler="ExampleTypeHandler"/>
  </typeHandlers>
  
  ......
  
</configuration>

也就是說,我們在自定義TypeHandler的時(shí)候,可以在TypeHandler通過@MappedJdbcTypes指定jdbcType, 通過 @MappedTypes 指定javaType,如果沒有使用注解指定,那么我們就需要在配置文件中配置。

objectFactory

objectFactory是干什么的? 需要配置嗎?

MyBatis 每次創(chuàng)建結(jié)果對象的新實(shí)例時(shí),它都會(huì)使用一個(gè)對象工廠(ObjectFactory)實(shí)例來完成。默認(rèn)的對象工廠需要做的僅僅是實(shí)例化目標(biāo)類,要么通過默認(rèn)構(gòu)造方法,要么在參數(shù)映射存在的時(shí)候通過參數(shù)構(gòu)造方法來實(shí)例化。默認(rèn)情況下,我們不需要配置,mybatis會(huì)調(diào)用默認(rèn)實(shí)現(xiàn)的objectFactory。 除非我們要自定義ObjectFactory的實(shí)現(xiàn), 那么我們才需要去手動(dòng)配置。

那么怎么自定義實(shí)現(xiàn)ObjectFactory? 怎么配置呢?自定義ObjectFactory只需要去繼承DefaultObjectFactory(是ObjectFactory接口的實(shí)現(xiàn)類),并重寫其方法即可。具體的,本處不多說,后面再具體講解。

寫好了ObjectFactory, 僅需做如下配置:

<configuration>
    ......
    <objectFactory type="org.mybatis.example.ExampleObjectFactory">
        <property name="someProperty" value="100"/>
    </objectFactory>
    ......
</configuration>

objectFactoryElement源碼:

/**
 * objectFactory 節(jié)點(diǎn)解析
 */
private void objectFactoryElement(XNode context) throws Exception {
    if (context != null) {
      //讀取type屬性的值, 接下來進(jìn)行實(shí)例化ObjectFactory, 并set進(jìn) configuration
      //到此,簡單講一下configuration這個(gè)對象,其實(shí)它里面主要保存的都是mybatis的配置
      String type = context.getStringAttribute("type");
      //讀取propertie的值, 根據(jù)需要可以配置, mybatis默認(rèn)實(shí)現(xiàn)的objectFactory沒有使用properties
      Properties properties = context.getChildrenAsProperties();
      
      ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
      factory.setProperties(properties);
      configuration.setObjectFactory(factory);
    }
 }

plugins

plugin有何作用? 需要配置嗎?

plugins 是一個(gè)可選配置。mybatis中的plugin其實(shí)就是個(gè)interceptor, 它可以攔截Executor 、ParameterHandler 、ResultSetHandler 、StatementHandler 的部分方法,處理我們自己的邏輯。Executor就是真正執(zhí)行sql語句的東西, ParameterHandler 是處理我們傳入?yún)?shù)的,還記得前面講TypeHandler的時(shí)候提到過,mybatis默認(rèn)幫我們實(shí)現(xiàn)了不少的typeHandler, 當(dāng)我們不顯示配置typeHandler的時(shí)候,mybatis會(huì)根據(jù)參數(shù)類型自動(dòng)選擇合適的typeHandler執(zhí)行,其實(shí)就是ParameterHandler 在選擇。ResultSetHandler 就是處理返回結(jié)果的。

怎么自定義plugin ? 怎么配置?要自定義一個(gè)plugin, 需要去實(shí)現(xiàn)Interceptor接口,這兒不細(xì)說,后面實(shí)戰(zhàn)部分會(huì)詳細(xì)講解。定義好之后,配置如下:

<configuration>
    ......
    <plugins>
      <plugin interceptor="org.mybatis.example.ExamplePlugin">
        <property name="someProperty" value="100"/>
      </plugin>
    </plugins>
    ......
</configuration>

pluginElement源碼:

/**
   * plugins 節(jié)點(diǎn)解析
   */
  private void pluginElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        String interceptor = child.getStringAttribute("interceptor");
        Properties properties = child.getChildrenAsProperties();
        //由此可見,我們在定義一個(gè)interceptor的時(shí)候,需要去實(shí)現(xiàn)Interceptor, 這兒先不具體講,以后會(huì)詳細(xì)講解
        Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
        interceptorInstance.setProperties(properties);
        configuration.addInterceptor(interceptorInstance);
      }
    }
  }

mappers

mappers, 這下引出mybatis的核心之一了,mappers作用 ? 需要配置嗎?

mappers 節(jié)點(diǎn)下,配置我們的mapper映射文件, 所謂的mapper映射文件,就是讓mybatis 用來建立數(shù)據(jù)表和javabean映射的一個(gè)橋梁。在我們實(shí)際開發(fā)中,通常一個(gè)mapper文件對應(yīng)一個(gè)dao接口, 這個(gè)mapper可以看做是dao的實(shí)現(xiàn)。所以,mappers必須配置。

<configuration>
    ......
    <mappers>
        <!-- 第一種方式:通過resource指定 -->
        <mapper resource="com/dy/dao/userDao.xml"/>
    
        <!-- 第二種方式, 通過class指定接口,進(jìn)而將接口與對應(yīng)的xml文件形成映射關(guān)系
             不過,使用這種方式必須保證 接口與mapper文件同名(不區(qū)分大小寫), 
             我這兒接口是UserDao,那么意味著mapper文件為UserDao.xml 
        <mapper class="com.dy.dao.UserDao"/>
        -->
      
        <!-- 第三種方式,直接指定包,自動(dòng)掃描,與方法二同理 
        <package name="com.dy.dao"/>
        -->
        <!-- 第四種方式:通過url指定mapper文件位置
        <mapper url="file://........"/>
        -->
    </mappers>
    ......
</configuration>

mapperElement源碼:

/**
   * mappers 節(jié)點(diǎn)解析
   * 這是mybatis的核心之一
   */
  private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          //如果mappers節(jié)點(diǎn)的子節(jié)點(diǎn)是package, 那么就掃描package下的文件, 注入進(jìn)configuration
          String mapperPackage = child.getStringAttribute("name");
          configuration.addMappers(mapperPackage);
        } else {
          String resource = child.getStringAttribute("resource");
          String url = child.getStringAttribute("url");
          String mapperClass = child.getStringAttribute("class");
          //resource, url, class 三選一
          
          if (resource != null && url == null && mapperClass == null) {
            ErrorContext.instance().resource(resource);
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //mapper映射文件都是通過XMLMapperBuilder解析
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url != null && mapperClass == null) {
            ErrorContext.instance().resource(url);
            InputStream inputStream = Resources.getUrlAsStream(url);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url == null && mapperClass != null) {
            Class<?> mapperInterface = Resources.classForName(mapperClass);
            configuration.addMapper(mapperInterface);
          } else {
            throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
          }
        }
      }
    }
  }

settings

<settings> 
    <setting name="cacheEnabled" value="true"/> 
    <setting name="lazyLoadingEnabled" value="true"/> 
    <setting name="multipleResultSetsEnabled" value="true"/> 
    <setting name="useColumnLabel" value="true"/> 
    <setting name="useGeneratedKeys" value="false"/> 
    <setting name="enhancementEnabled" value="false"/> 
    <setting name="defaultExecutorType" value="SIMPLE"/> 
    <setting name="defaultStatementTimeout" value="25000"/> 
</settings>

setting節(jié)點(diǎn)里配置的值會(huì)直接改寫Configuration對應(yīng)的變量值,這些變量描述的是Mybatis的全局運(yùn)行方式,如果對這些屬性的含義不熟悉的話建議不要配置,使用默認(rèn)值即可。

settingsElement:

private void settingsElement(XNode context) throws Exception {
    if (context != null) {
      Properties props = context.getChildrenAsProperties();
      // Check that all settings are known to the configuration class
      MetaClass metaConfig = MetaClass.forClass(Configuration.class);
      for (Object key : props.keySet()) {
        if (!metaConfig.hasSetter(String.valueOf(key))) {
          throw new BuilderException("The setting " + key + " is not known.  Make sure you spelled it correctly (case sensitive).");
        }
      }
      configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
      configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
      configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
      configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
      configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), true));
      configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
      configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
      configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
      configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
      configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
      configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
      configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
      configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
      configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
      configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
      configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
      configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
      configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
      configuration.setLogPrefix(props.getProperty("logPrefix"));
      configuration.setLogImpl(resolveClass(props.getProperty("logImpl")));
      configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
    }
}


責(zé)任編輯:武曉燕 來源: seven97
相關(guān)推薦

2023-06-26 13:08:52

GraphQL服務(wù)數(shù)據(jù)

2024-06-12 08:36:25

2024-02-05 13:52:30

?Thread對象強(qiáng)引用

2023-12-27 07:31:45

json產(chǎn)品場景

2024-10-11 09:15:33

2022-07-11 09:00:37

依賴配置文件Mybati

2023-04-27 08:18:10

MyBatis緩存存儲(chǔ)

2023-06-27 08:00:35

2024-08-19 10:24:14

2022-10-24 09:55:32

ESLintJavaScript

2024-09-06 07:29:05

2022-12-22 08:14:54

2023-01-10 08:43:15

定義DDD架構(gòu)

2024-02-04 00:00:00

Effect數(shù)據(jù)組件

2023-07-26 13:11:21

ChatGPT平臺(tái)工具

2024-01-19 08:25:38

死鎖Java通信

2024-01-02 12:05:26

Java并發(fā)編程

2023-08-01 12:51:18

WebGPT機(jī)器學(xué)習(xí)模型

2023-10-13 09:04:09

2024-07-31 08:26:47

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號