1. 程式人生 > >MyBatis原始碼分析:SqlSession獲取過程

MyBatis原始碼分析:SqlSession獲取過程

public static void main(String[] args) throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //SqlSessionFactory初始化
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //獲取SqlSession
SqlSession session = factory.openSession(); UserMapper userMapper = session.getMapper(UserMapper.class); User user = userMapper.getUserById("1"); System.out.println(user); }

1、SqlSessionFactory初始化過程

//class:SqlSessionFactoryBuilder
public SqlSessionFactory build
(InputStream inputStream, String environment, Properties properties) { try { //建立XML解析器來解析xml配置檔案 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); //parser.parse()解析xml檔案 return build(parser.parse()); } catch (Exception e) { throw
ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } //返回包含了Configuration的DefaultSqlSession物件。 public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }
//把配置檔案的資訊解析並儲存在Configuration物件中 
public Configuration parse() {
      //如果已經解析過了,丟擲異常
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
      //配置檔案的根節點是configuration
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

解析配置檔案:

分步驟解析xml檔案的各個節點

private void parseConfiguration(XNode root) {
    try {
      Properties settings = settingsAsPropertiess(root.evalNode("settings"));
      //issue #117 read properties first
      //解析properties
      propertiesElement(root.evalNode("properties"));
      //解析settings
      loadCustomVfs(settings);
      //解析typeAliases,類型別名
      typeAliasesElement(root.evalNode("typeAliases"));
      //解析外掛
      pluginElement(root.evalNode("plugins"));
      //解析物件工廠
      objectFactoryElement(root.evalNode("objectFactory"));
      //解析物件包裝工廠
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      //解析reflectorFactory
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      //把settings裡各個所有設定設定到configruation上
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      //解析environments
      environmentsElement(root.evalNode("environments"));
      //解析databaseIdProvider
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      //解析typeHandlers,型別處理器
      typeHandlerElement(root.evalNode("typeHandlers"));
      //解析mappers
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

Mybatis會把配置檔案的所有資訊都儲存在Configuration物件中,並返回包含了configuration的DefualtSqlSessionFactoryd物件
configuration物件:

這裡寫圖片描述

主要過程:

​ 解析xml的每一個資訊儲存在Configuration中,返回包含Configuration的DefaultSqlSessionFactory;

2、SqlSession獲取

SqlSession session = factory.openSession();
  //class:DefaultSqlSessionFactory
  @Override
  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      //通過事務工廠來產生一個事務
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //生成一個執行器
      final Executor executor = configuration.newExecutor(tx, execType);
      //構建DefaultSqlSession物件並返回
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

執行器Executor建立過程:

//根據傳入的ExecutorType來構建不同的Executor,可以在配置檔案中配置,預設是SIMPLE
//final Executor executor = configuration.newExecutor(tx, execType);
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
     //如果要求快取,生成另一種CachingExecutor(預設就是有快取),裝飾者模式,所以預設都是返回CachingExecutor
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    //此處呼叫外掛,通過外掛可以改變Executor行為,採用的是責任鏈模式,來產生代理物件
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

SqlSession物件中包含configuration和executor
這裡寫圖片描述

主要過程:

​ 1、根據ExecutorType建立Executor,預設是SIMPLE型別的,但因為cacheEnabled預設是為true的,所以實際上生成的是CachingExecutor,裡面包含了一個Executor,使用了裝飾者模式;

​ 2、返回一個DefaultSqlSession物件,該物件包含Configuration和Executor;