Mybatis源码(一):SqlSessionFactory

在Mybatis中,SqlSessionFactory 是一个重要对象,用来创建 SqlSession,而 SqlSession 是用来操作数据库的。

一. SqlSessionFactory 的生成
我们先来看一段代码:

  private static SqlSessionFactory sqlMapper;

  @BeforeAll
  static void setup() throws Exception {
    createBlogDataSource();
    final String resource = "org/apache/ibatis/builder/MapperConfig.xml";
    final Reader reader = Resources.getResourceAsReader(resource);
    sqlMapper = new SqlSessionFactoryBuilder().build(reader);
  }

这是一段摘自mybatis测试用例的代码,逻辑是:从一个路径中获取到字符流,通过 SqlSessionFactoryBuilder 的 builder 方法创建 SqlSessionFactoryBuilder。
我们来看下 SqlSessionFactoryBuilder 的源码:

public class SqlSessionFactoryBuilder {

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

  // mybatis 可以在不同环境下切换数据源
  // 也可以通过 environments 标签的 default 属性指明默认环境
  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());
    } 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.
      }
    }
  }

  public SqlSessionFactory build(InputStream inputStream) {
    return build(inputStream, null, null);
  }

  public SqlSessionFactory build(InputStream inputStream, String environment) {
    return build(inputStream, environment, null);
  }

  public SqlSessionFactory build(InputStream inputStream, Properties properties) {
    return build(inputStream, null, properties);
  }

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      // 从流中解析出 Configuration
      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.
      }
    }
  }

  /**
   * 返回 DefaultSqlSessionFactory
   */
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

}

不难看出,SqlSessionFactoryBuilder 主要有两类 build 方法,一类加载字节流,一类加载字符流。对应 XMLConfigBuilder 的两种流解析方法。XMLConfigBuilder 从流中解析出另外一个很重要的对象:Configuration(这个后续再说)。而最终,调用 build(Configuration config) 方法,返回一个SqlSessionFactory(DefaultSqlSessionFactory) 。

二、SqlSessionFactory
SqlSessionFactory 主要作用是从 Connection 或 DataSource 中创建一个SqlSession, 其次提供获取 Configuration 的方法。

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();

}

三、DefaultSqlSessionFactory
DefaultSqlSessionFactory 是 SqlSessionFactory 的默认实现

public class DefaultSqlSessionFactory implements SqlSessionFactory {

  // mybatis 核心 环境配置
  private final Configuration configuration;

  public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
  }

  @Override
  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

  @Override
  public SqlSession openSession(boolean autoCommit) {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
  }

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

  @Override
  public SqlSession openSession(TransactionIsolationLevel level) {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), level, false);
  }

  @Override
  public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
    return openSessionFromDataSource(execType, level, false);
  }

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

  @Override
  public SqlSession openSession(Connection connection) {
    return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
  }

  @Override
  public SqlSession openSession(ExecutorType execType, Connection connection) {
    return openSessionFromConnection(execType, connection);
  }

  @Override
  public Configuration getConfiguration() {
    return configuration;
  }

  /**
   * 1. 这里有个 ExecutorType 枚举了 SIMPLE, REUSE, BATCH 三种执行器
   * 实际上还有第四种执行器 {@link org.apache.ibatis.executor.CachingExecutor}
   * 这个执行器是在开启了 Mybatis 二级缓存后使用的,它使用装饰者模式
   * 包装 SIMPLE, REUSE, BATCH 三种执行器提供缓存功能
   * 2. 事务隔离级别,是一个枚举型,包括JDBC支持的5个级别
   * 3. 是否自动提交事务
   */
  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      // 获取 environment
      final Environment environment = configuration.getEnvironment();
      // 获取事务工厂
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      // 创建执行器
      final Executor executor = configuration.newExecutor(tx, execType);
      // 返回 SqlSession (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();
    }
  }


  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
        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);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  /**
   * 获取事务工厂
   */
  private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
    // 如果 environment 为 null 或者其事务工厂为 null
    if (environment == null || environment.getTransactionFactory() == null) {
      // 返回 ManagedTransactionFactory 事务工厂
      // Mybatis 管理事务的两种方式
      // 1. 使用 JDBC 的事务管理机制,就是利用 java.sql.Connection 对象完成对事务的提交
      // 2. 使用 MANAGED 的事务管理机制,这种机制 mybatis 自身不会去实现事务管理,
      // 而是让程序的WEB容器(JBOSS,WebLogic,Tomcat)来实现对事务的管理,
      // 所有它对事务提交和回滚并不会做任何操作
      return new ManagedTransactionFactory();
    }
    // environment 有两个重要属性。
    // DataSource 和 TransactionFactory
    // 即数据源和事务工厂
    return environment.getTransactionFactory();
  }

  private void closeTransaction(Transaction tx) {
    if (tx != null) {
      try {
        tx.close();
      } catch (SQLException ignore) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

}

我们看下 TransactionIsolationLevel

public enum TransactionIsolationLevel {
  /**
   * 无事务
   */
  NONE(Connection.TRANSACTION_NONE),

  /**
   * 读已提交数据,防止脏读,不能处理幻读和不可重复读 (Oracle)
   */
  READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),

  /**
   * 读未提交数据,可能出现任何事务并发问题,什么都不处理,性能最好
   */
  READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),

  /**
   * 可重复读,防止脏读和幻读,性能比SERIALIZABLE好(MySql)
   */
  REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),

  /**
   * 串行化,不会出现任何并发问题,但是性能最差
   */
  SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE);

  private final int level;

  TransactionIsolationLevel(int level) {
    this.level = level;
  }

  public int getLevel() {
    return level;
  }

}

你可能感兴趣的:(mybatis,java,mybatis)