Mybatis|SessionFactory机制原理

Mybatis|SessionFactory机制原理_第1张图片

1. SqlSessionFactory基本介绍

SqlSessionFactory是MyBatis框架中的一个接口,主要负责MyBatis框架初始化操作及为开发人员提供SqlSession对象。SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象类获得,SqlSessionFactoryBuilder可以从XML配置文件或一个预先定制的Configuration的实例构建出SqlSessionFactory的实例。

//通过openSession方法获得sqlSession
public interface SqlSessionFactory {

  SqlSession openSession();
  
  SqlSession openSession(boolean autoCommit);//事务是手动提交还是自动提交
  SqlSession openSession(Connection 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();

}

openSession方法重载的目的主要是帮助开发人员根据自己的需要得到一个openSession

SqlSessionFactory有两个实现类:

  • SqlSessionManager(被抛弃)
    SqlSessionManager是用来进行线程安全控制的,看第三行代码,ThreadLocal是做线程安全的,把SqlSession放入了当前用户线程中。因为在实际开发中MyBatis是和Sring框架是一起用的,线程安全由Spring框架来处理了,所以它被抛弃了。
  private final SqlSessionFactory sqlSessionFactory;
  private final SqlSession sqlSessionProxy;

  private final ThreadLocal localSqlSession = new ThreadLocal();

  private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
    this.sqlSessionFactory = sqlSessionFactory;
    this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[]{SqlSession.class},
        new SqlSessionInterceptor());
  }
  • DefaultSqlSessionFactory
    直接看源码,看DefaultSqlSessionFactory结构可以看到它就一个属性Configuration,configuration在内存中存储了MyBatis框架中相关配置文件信息。
    找到openSessionFromDataSource方法,里面有三个参数:
    ExecutorType:执行器的类型。默认类型时simple
    TransactionIsolationLevel:数据库隔离级别。
    autoCommit:是否支持手动事务提交。

由于代码太多,直接看源码中的注释。

/**
 * @author Clinton Begin
 */
public class DefaultSqlSessionFactory implements SqlSessionFactory {

  private final Configuration configuration;

  //传入配置文件生成的对象
  public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
  }
  
  @Override
  public SqlSession openSession() {
    return 
openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);//告诉我们如何去建一个sqlSssion
  }
  //autoCommit true支持事务  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);
  }
  
  //执行类型,有4种,BatchExecutor、ReuseExecutor、SimpleExecutor和CachingExecutor
  @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;
  }

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      //读取环境变量(配置文件中标签里面内容)  
      final Environment environment = configuration.getEnvironment();
      //通过环境变量获取当前事务的管理方式,配置文件中的transactionManager 元素配置的type来选择事务
     
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      //事务管理对象
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //获取执行器
      //execType是sql操作类型
      //BatchExecutor用于执行批量sql操作
      //ReuseExecutor会重用statement执行sql操作
      //SimpleExecutor简单执行sql操作
      //CachingExecutor 在查找数据库前先查找缓存,若没有找到的话调用delegate从数据库查询,并将查询结果存入缓存中。
      final Executor executor = configuration.newExecutor(tx, execType);
      //configuration, executor, autoCommit打包交给DefaultSqlSession(sqlSession实现类)
      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();
    }
  }
  //事务工厂,mybatis对于事务的管理有两种形式,
  //使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交
  //使用MANAGED的事务管理机制,这种机制mybatis自身不会去实现事务管理,交给Spring来实现对事务的管理
  private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
    if (environment == null || environment.getTransactionFactory() == null) {
      return new ManagedTransactionFactory();
    }
    return environment.getTransactionFactory();
  }

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

2. 创建SqlSessionFactory基本执行流程

  1. 调用 SqlSessionFactoryBuilder 对象的 build(inputStream) 方法;

  2. SqlSessionFactoryBuilder 会根据输入流 inputStream 等信息创建XMLConfigBuilder 对象 ; Dom4j.jar

  3. SqlSessionFactoryBuilder 调用 XMLConfigBuilder 对象的 parse() 方法;

  4. XMLConfigBuilder 对象返回 Configuration 对象;

  5. SqlSessionFactoryBuilder创建一个DefaultSessionFactory 对象,并将Configuration对象作为参数传给DefaultSessionFactory对象;

  6. SqlSessionFactoryBuilder 返回 DefaultSessionFactory 对象给 Client ,供 Client使用。
    Client可以使用DefaultSessionFactory对象创建需要的SqlSession.

public class SqlSessionFactoryBuilder {

  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);//一个XML文档只能解析一次parsed否则抛异常
      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);
      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.
      }
    }
  }
    
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }
}

上面初始化过程中设计到几个对象:

  • SqlSessionFactoryBuilder :SqlSessionFactory的构造器,用于创建SqlSessionFactory,采用了建造者设计模式。
  • Configuration :该对象是mybatis-config.xml文件中所有mybatis配置信息。
  • SqlSessionFactory:SqlSession工厂类,以工厂形式创建SqlSession对象,采用了Factory工厂设计模式。
  • XmlConfigParser :负责将mybatis-config.xml配置文件解析成Configuration对象,共SqlSessonFactoryBuilder使用,创建SqlSessionFactory。

3. SqlSessionFactory涉及的设计模式(Build建造者设计模式)

3.1 什么是建造者设计模式

使用多个简单的对象一步一步构建一个复杂的对象,这种模式属于创建型模式,目前是创建型的最佳模式。

3.2 SqlSessionFactoryBuilder与SqlSessionFactory之间关系
  • SqlSessionFactoryBuilder是Builder模式中建造者,负责SqlSessionFactory对象的创建以及
  • SqlSessionFactroy对象内部所需要内容的组装.
 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);
  }

4. Configuration介绍

MyBatis介绍支持开发人员通过配置文件与其进行交流,在配置文件中配置所有信息,在框架运行时,会被XMLConfigBuilder解析并存储在一个configuration对象中,donfiguratioin对象会被作为参数传送给DeFaultSQLSessionFacFactory,DeFaultSQLSessionFacFactory根据configuration对象信息为client创建对应特征的SqlSession对象。

private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(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);
    }
  }

解释一下上面那段源码,可以看见XML文件中中的所有内容都解析并放入到了XNode中剩下的只要调用XNode方法获取自己想要的内容即可。解析标签XPathParser的evalNode方法来解析为XNode的。XML解析可以熟悉一下Dom4j。

你可能感兴趣的:(Mybatis|SessionFactory机制原理)