mybatis筆記3 一些原理的理解


1,mybatis流程跟蹤,原理理解

  基本思路: 從SqlSessionFactory的初始化出發,觀察資源的准備和環境的准備,以及實現持久層的一些過程;

 

進入SqlSessionFactoryBean類,發現先執行的是

image

然后是:

image

在初始化類之后,做的准備工作如下:

public void afterPropertiesSet() throws Exception {
    notNull(dataSource, "Property 'dataSource' is required");//1,檢查spring准備的datasource是否ok
    notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");//2,檢查空構造方法的sqlSessionFactoryBuilder是否准備好

    this.sqlSessionFactory = buildSqlSessionFactory();//3,利用配置的屬性,構造sqlSessionFactory
  }

構造細節如下:方法有點長,注意注釋這個是流程,之后我畫一個圖來加深理解;

protected SqlSessionFactory buildSqlSessionFactory() throws IOException {

   Configuration configuration;

   XMLConfigBuilder xmlConfigBuilder = null;
   if (this.configLocation != null) {//1,檢查是否有配置configLocation,即mybatis的整體配置文件,非mapper文件,如果有加載進去,沒有,構造一個空的
     xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
     configuration = xmlConfigBuilder.getConfiguration();
   } else {
     if (logger.isDebugEnabled()) {
       logger.debug("Property 'configLocation' not specified, using default MyBatis Configuration");
     }
     configuration = new Configuration();
     configuration.setVariables(this.configurationProperties);
   }

   if (this.objectFactory != null) {//2,檢查對象工廠,如果有設置進去,沒有留空
     configuration.setObjectFactory(this.objectFactory);
   }

   if (this.objectWrapperFactory != null) {//3,檢查對象裝飾工廠,如果有設置進去,沒有留空

     configuration.setObjectWrapperFactory(this.objectWrapperFactory);
   }

   if (hasLength(this.typeAliasesPackage)) {//4,檢查包的簡稱,如果有注冊進去
     String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
         ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
     for (String packageToScan : typeAliasPackageArray) {
       configuration.getTypeAliasRegistry().registerAliases(packageToScan,
               typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
       if (logger.isDebugEnabled()) {
         logger.debug("Scanned package: '" + packageToScan + "' for aliases");
       }
     }
   }

   if (!isEmpty(this.typeAliases)) {//5,檢查類的簡稱,如果有注冊進去
     for (Class<?> typeAlias : this.typeAliases) {
       configuration.getTypeAliasRegistry().registerAlias(typeAlias);
       if (logger.isDebugEnabled()) {
         logger.debug("Registered type alias: '" + typeAlias + "'");
       }
     }
   }

   if (!isEmpty(this.plugins)) {//6,檢查插件,如果有注冊進去
     for (Interceptor plugin : this.plugins) {
       configuration.addInterceptor(plugin);
       if (logger.isDebugEnabled()) {
         logger.debug("Registered plugin: '" + plugin + "'");
       }
     }
   }

   if (hasLength(this.typeHandlersPackage)) {//7,檢查類型轉換類包,如果有注冊進去
     String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,
         ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
     for (String packageToScan : typeHandlersPackageArray) {
       configuration.getTypeHandlerRegistry().register(packageToScan);
       if (logger.isDebugEnabled()) {
         logger.debug("Scanned package: '" + packageToScan + "' for type handlers");
       }
     }
   }

   if (!isEmpty(this.typeHandlers)) {//8,檢查類型轉換類,如果有注冊進去
     for (TypeHandler<?> typeHandler : this.typeHandlers) {
       configuration.getTypeHandlerRegistry().register(typeHandler);
       if (logger.isDebugEnabled()) {
         logger.debug("Registered type handler: '" + typeHandler + "'");
       }
     }
   }

   if (xmlConfigBuilder != null) {//9,檢查是否有xml的構造器,如果有,直接使用構造器構造
     try {
       xmlConfigBuilder.parse();

       if (logger.isDebugEnabled()) {
         logger.debug("Parsed configuration file: '" + this.configLocation + "'");
       }
     } catch (Exception ex) {
       throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
     } finally {
       ErrorContext.instance().reset();
     }
   }

   if (this.transactionFactory == null) {//10,檢查事物工廠,如果沒有,構造一個spring管理的事物工廠
     this.transactionFactory = new SpringManagedTransactionFactory();
   }

//11,構造環境變量

   Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource);
   configuration.setEnvironment(environment);

   if (this.databaseIdProvider != null) {
     try {//12,檢查是否配置了db id,如果有,設置到配置的類中
       configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
     } catch (SQLException e) {
       throw new NestedIOException("Failed getting a databaseId", e);
     }
   }

   if (!isEmpty(this.mapperLocations)) {//13,把配置的mapper弄進來總配置文件里
     for (Resource mapperLocation : this.mapperLocations) {
       if (mapperLocation == null) {
         continue;
       }

       try {
         XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
             configuration, mapperLocation.toString(), configuration.getSqlFragments());
         xmlMapperBuilder.parse();
       } catch (Exception e) {
         throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
       } finally {
         ErrorContext.instance().reset();
       }

       if (logger.isDebugEnabled()) {
         logger.debug("Parsed mapper file: '" + mapperLocation + "'");
       }
     }
   } else {
     if (logger.isDebugEnabled()) {
       logger.debug("Property 'mapperLocations' was not specified or no matching resources found");
     }
   }

   return this.sqlSessionFactoryBuilder.build(configuration);//14,最后通過得到的配置類來構造一個sqlsessionFactory工廠
}

 

設置好屬性之后,執行

image

得到factory構造的bean,即sqlSessionFactory,

最后容器啟動成功的事件監控

public void onApplicationEvent(ApplicationEvent event) {
   if (failFast && event instanceof ContextRefreshedEvent) {
     // fail-fast -> check all statements are completed
     this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
   }
}

以上是資源的准備,下面來一次增刪改查的跟蹤,觀察內部的工作原理;

 

查詢單條記錄的過程:

 

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  try {
    MappedStatement ms = configuration.getMappedStatement(statement);//1,通過轉換,得到存儲的mapperedStatement
    List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);//2,轉換成jdbc代碼執行
    return result;
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}

內部就像是一台精密的儀器,去除了大量的模版jdbc代碼;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM