MyBatis(六):SqlSession执行源码分析

SqlSession执行源码分析

针对以下代码

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static{
        InputStream inputStream = null;
        try {
        //使用输入流读取文件 String resource = "mybatis-config.xml"; inputStream = Resources.getResourceAsStream(resource); //现在我们分析这一行代码 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } }
public static SqlSession getSqlSession(){
    return sqlSessionFactory.openSession();
}
      
 

 

 

该行代码:

      sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

1.实例化SqlSessionFactoryBuilde()对象。

2.执行build方法

  • 实际上build方法有9个,这里只列出相关的2个。

//先走这里,实际是为了走下面的build方法,把enviroment和properties都给null
public SqlSessionFactory build(InputStream inputStream) {
    return build(inputStream, null, null);
}
//真正要走的build方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
        //a.这一行其实不重要,就是通过几个构造器把InputStream换成了XMLConfigBuilder
        XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
        //b.通过XMLConfigBuilder.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.
        }
    }
}
​

 

a.实例化XMLConfigBuilder

        //a.实例化XMLConfigBuilder
        XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);

a-1.XMLConfigBuilder构造器

 
//后面两个参数都是空,可以忽略,因此关键是new XPathParser(inputStream, true, props, new XMLMapperEntityResolver())
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
  }

a-2. XPathParser构造器

  
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
  //一般走的构造器properties是空的,但是如果给了properties,那么就会在这里赋值给configuration的属性properties    
  commonConstructor(validation, variables, entityResolver); //在这里把InputStream类换成Document类 this.document = createDocument(new InputSource(inputStream)); }

 


b-1.通过XMLConfigBuilder.parse()对xml文件解析

        //b.通过XMLConfigBuilder.parse()对xml文件解析
        (parser.parse())

 

b-2.parse方法

  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
      //parseConfiguration方法解析xml
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }
​

 

b-3.parseConfiguration方法解析xml

//这个方法里就可以看到很多我们熟悉的设置了:properties,settings,typeAliases...
private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
        //properties设置,以这个为例
      propertiesElement(root.evalNode("properties"));
        
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      loadCustomLogImpl(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }
​

 

b-4.propertiesElement(root.evalNode("properties"));

  private void propertiesElement(XNode context) throws Exception {
    if (context != null) {
        //把xml文件<properties>中<property>的所有参数名、参数值以键值对放在defaults中
      Properties defaults = context.getChildrenAsProperties();
        //获取resource和url的参数值
      String resource = context.getStringAttribute("resource");
      String url = context.getStringAttribute("url");
        //resource和url只能有1个
      if (resource != null && url != null) {
        throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
      }
        //把db.properties文件中的值放入到defaults中,注意上面是xml的properties配置,这里是文件
        //因此properties文件是后覆盖的,优先级比xml文件要高
      if (resource != null) {
        defaults.putAll(Resources.getResourceAsProperties(resource));
      } else if (url != null) {
        defaults.putAll(Resources.getUrlAsProperties(url));
      }
        //查看configuration是否已经有属性了,如果有,就覆盖到defaults中
        //这个实际上是build构造器中输入的属性值,在new SqlSessionFactoryBuilder().build(inputStream)方法中有输入的话,会在上文的a代码中写入到configuration类中。
        //说明这里的构造器输入的优先级是最高的
      Properties vars = configuration.getVariables();
      if (vars != null) {
        defaults.putAll(vars);
      }
      parser.setVariables(defaults);
        //把default传入到configuration类中
      configuration.setVariables(defaults);
    }
  }
​

 

b-5.返回到了最初的new SqlSessionFactoryBuilder().build(inputStream)方法的主线中

注意这时候我们走完的是parser.parser()

       //b.通过XMLConfigBuilder.parse()对xml文件解析
        return build(parser.parse());

 

实际上,接着要走的是build(configuration)

 public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

 

返回了 DefaultSqlSessionFactory的示例

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static{
        InputStream inputStream = null;
        try {
            String resource = "mybatis-config.xml";
            inputStream = Resources.getResourceAsStream(resource);
            //现在SqlSessionFactory实例化成功了,注意这里其实是多态:
            //类似:SqlSessionFactory sqlSessionFactory = new DefaultSqlSessionFactory();
            //SqlSessionFactory是一个接口,被DefaultSqlSessionFactory继承
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
​
    //创建对象
    public static SqlSession getSqlSession(){
        //因此这个openSession方法实际上是被DefaultSqlSessionFactory重写的方法
        return sqlSessionFactory.openSession();
    }
}

 

3.DefaultSqlSessionFactory.openSession();

 @Override
  public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
    return openSessionFromDataSource(execType, null, autoCommit);
  }
​

 

3-1.openSessionFromDataSource(execType, null, autoCommit);

 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
        // 获取mybati-config.xml中配置的environment对象
      final Environment environment = configuration.getEnvironment();
        // 获取事务工厂对象
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
        // 创建事务
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        // 创建Executor对象
      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();
    }
  }
​

 

  1. SqlSession也是多态,实际对象是DefaultSqlSession

  2. 事务和Executor在创建SqlSession以前就已经创建了

  3. Executor的源码如下,简单浏览应该是执行sql的类。下次再继续查看

public interface Executor {
​
  ResultHandler NO_RESULT_HANDLER = null;
​
  int update(MappedStatement ms, Object parameter) throws SQLException;
​
  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;
​
  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;
​
  <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;
​
  List<BatchResult> flushStatements() throws SQLException;
​
  void commit(boolean required) throws SQLException;
​
  void rollback(boolean required) throws SQLException;
​
  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
​
  boolean isCached(MappedStatement ms, CacheKey key);
​
  void clearLocalCache();
​
  void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
​
  Transaction getTransaction();
​
  void close(boolean forceRollback);
​
  boolean isClosed();
​
  void setExecutorWrapper(Executor executor);
​
}

 


 

posted @ 2020-03-28 00:26  renzhongpei  阅读(423)  评论(0编辑  收藏  举报