Mybatis源码解析5——SqlSessionFactory

在Executor的解析一篇中我已经大致的分析了SqlSessionFactory对于创建SqlSession的工作,现在来进一步的探讨一下SqlSessionFactory的全部内容。

回顾之前的研究,已经知道SqlSessionFactory的一部分工作是创建SqlSession,SqlSessionFactory是一个接口,这个接口限定openSession返回的session必需是从连接或数据源创建的:

/**
 * Creates an {@link SqlSession} out of a connection or a DataSource
 * //创建一个必需是从连接或数据源创建的SqlSession
 * @author Clinton Begin
 */
public interface SqlSessionFactory {

  SqlSession openSession();//实际用到的只有这两个方法
  SqlSession openSession(boolean autoCommit);
  SqlSession openSession(Connection connection);//这个接口方法及下面的方法均是用户管理方法
  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  SqlSession openSession(ExecutorType execType, Connection connection);

  Configuration getConfiguration();

}
它的两个实现子类分别是:

Mybatis源码解析5——SqlSessionFactory_第1张图片

现在聚焦DefaultSqlSessionFactory,了解他是如何创建SqlSession的。Sqlsession不负责创建executor,那么executor也是由factory负责创建并传入给session的。创建session都是通过下面两个核心方法产生,一个通过数据源产生,另一个直接由连接对象产生,其实大同小异,数据源只是对连接做了一个封装而已。关键是根据传入的executor类型参数来决定创建哪一种executor,而他们最终都是创建DefaultSqlSession并返回:

  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);//传入类型创建executor
      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();
    }
  }

  private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
    try {
      boolean autoCommit;
      try {
        autoCommit = connection.getAutoCommit();
      } catch (SQLException e) {
        // Failover to true, as most poor drivers
        // or databases won't support transactions一些低级的DB驱动或者DB可能不支持事务,也就是只能必需提交,为应对这些情况设置为true
        autoCommit = true;
      }      
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      final Transaction tx = transactionFactory.newTransaction(connection);
      final Executor executor = configuration.newExecutor(tx, execType);//传入类型创建executor
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

参考SqlSession的族系模式,这个DefaultSqlSessionFactory也是基础实现,而SqlSessionManager在之前解读SqlSession的时候出现的,它同时还持有一个DefaultSqlSessionFactory,也就是对DefaultSqlSessionFactory的一个包装。根据我上面接口中给出的注释,这个SqlSessionManager同时实现session和factory接口,是为了给用户提供方便,可以直接指定使用Executor的类型,而是整合了SqlSession和SqlSessionFactory的方法。

在实际中,我们可以这样使用SqlSessionManager来方便使用

	public int update(int id) throws IOException {
		SqlSessionManager manager = SqlSessionManager.newInstance(Resources.getResourceAsReader("com/config/mybatis-config.xml"));
		manager.startManagedSession(ExecutorType.REUSE);//创建指定类型的Executor包含在SqlSession内
		int i = manager.update(namespace+"updateOne",id);//此时的manager就是一个session
		manager.commit();
		manager.close();
		return i;
	}

同时此时使用的session是线程安全的,我在第一篇SqlSession中讲到,这里就不再重复。另外需要注意的一点,如果通过下面的方式开启session,那么这个session是新建的非线程安全,因为manager又是factory,通过factory的方法创建session:

SqlSession session = manager.openSession();

并且它作为factory是不能保证factory单例的:

  public static SqlSessionManager newInstance(Reader reader) {
    return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
  }

前面说了这么多,终于轮到研究SqlSessionFactory是怎么来的了,SqlSessionManager是扩展的用户管理类,和mybatis其实关系不大,关键是DefaultSqlSessionFactory,它的创建很简单,通过SqlSessionFactoryBuilder的build方法来创建:

  public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }

  public SqlSessionFactory build(Reader reader, String environment) {
    return build(reader, environment, null);
  }

  public SqlSessionFactory build(Reader reader, Properties properties) {
    return build(reader, null, properties);
  }

  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);//解析配置文件
      return build(parser.parse());//调用SqlSessionFactory构造方法创建factory
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

这就是我们熟知的起手方法了:

static{
		String resource = "com/config/mybatis-config.xml";
		try {
			sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

最后总结一下,SqlSessionFactory是一个接口,它限定了创建session接口实现的方法,这些方法分为系统使用和用户扩展,SqlSessionManager既实现SqlSessionFactory接口,又实现了SqlSession接口,它是一个扩展用户管理类,可以直接创建所需类型的executor并执行查询。DefaultSqlSessionFactory是SqlSessionFactory的实现子类,实现了Session的创建基础方法,通过SqlSessionFactoryBuilder来创建DefaultSqlSessionFactory即可得到SqlSessionFactory并创建SqlSession。

结构图如下:

Mybatis源码解析5——SqlSessionFactory_第2张图片




你可能感兴趣的:(源码解析)