Mybatis source code analysis 3 - creation of sqlSession

1 Introduction and main classes

After initializing mybatis, that is, after creating the singleton SqlSessionFactory, it enters the running phase of mybatis. Each run of mybatis is carried out through the SqlSession object, which is the core of the runtime. Unlike SqlSessionFactory, SqlSession is not thread-safe, so it is generally recommended to define it in a local scope and close it after use. It is very simple for us to use mybatis to create SqlSession, the code is as follows

// 读入xml配置文件
String resource = "main/resources/SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建SqlSessionFactory,初始化mybatis的关键所在,上一节分析过了
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 利用SqlSessionFactory来创建SqlSession,这一节重点分析
SqlSession session = sessionFactory.openSession();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Creating a SqlSession is very simple, just call the openSession() method of SqlSessionFactory. But behind this method is actually quite complicated, mybatis does a lot of behind-the-scenes work for us. Let's first introduce the main classes used in the openSession() process.

  1. DefaultSqlSessionFactory : The default implementation class of SqlSessionFactory, which we mentioned in the previous section.
  2. Transaction : database transaction, there are two implementations of JdbcTransaction and ManagedTransaction
  3. Executor : The real implementation of the scheduler, sqlSession's select update and other methods, the core of mybatis operation.
  4. DefaultSqlSession : The default implementation class of sqlSession, and its methods are almost all implemented by the Executor proxy.

2 Process Analysis

Let's start with the openSession() method of DefaultSqlSessionFactory, the default factory class.

// SqlSessionFactory单例创建并开启一个sqlSession实例。sqlSession线程不安全,一般存放在局部作用域中,用完close即可。
public SqlSession openSession() {
  return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}

// 开启sqlSession
  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      // 获取configuration的environment,它代表了运行的数据库环境,
      // 由配置文件中的environments节点的environment子节点生成,创建SqlSessionFactory时指定其id,默认为default
      final Environment environment = configuration.getEnvironment();

      // environment实例中取出transactionFactory成员变量,然后实例化它。
      // JdbcTransactionFactory创建JdbcTransaction,使用JDBC代理管理commit等事务
      // ManagedTransactionFactory创建ManagedTransaction,自身不对事务进行处理,完全交给容器,如Spring
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

      // 由事务transaction创建调度器Executor,SqlSession的几乎所有方法都是通过代理模式由Executor真正实现
      // Executor代表调度器,由他来调度StatementHandler ParameterHandler ResultSetHandler。四者合称SqlSession四大组件
      // ExecutorType在XML配置文件的settings节点中设置(defaultExecutorType), 可以取SIMPLE REUSE BATCH,默认为SIMPLE
      // SIMPLE表示简易执行器,REUSE为一种执行器重用预处理语句,BATCH则为批量专用的执行器。
      final Executor executor = configuration.newExecutor(tx, execType);

      // 构造SqlSession实例,mybatis默认的实现类为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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

mybatis先由初始化阶段创建在configuration中的environment变量来创建数据库事务,然后根据XML配置文件的settings节点中设置的defaultExecutorType来创建调度器Executor,最后就可以创建得到DefaultSqlSession实例了。下面我们来分析事务的创建

2.1 数据库事务Transaction的创建

Transaction有两个实现类,即JdbcTransaction和ManagedTransaction,他们分别由JdbcTransactionFactory和ManagedTransactionFactory工厂类来创建实例。JdbcTransaction本地事务由数据库本身来管理事务,其getConnection()从DataSource中得到, commit() rollback() close() 则由java.sql.Connection实例代理实现。

ManagedTransaction由容器来管理事务,其getConnection()从DataSource中得到,commit() rollback()均为空实现,不做任何事情,完全托管给容器。

下面以JDBCTransaction为例来看Transaction事务的创建

  // 工厂类来创建事务实例
  // @Param DataSource: 数据库源
  // @Param level: 事务隔离级别,定义并发事务的处理方式。如A读时,B在写。
  // @param autoCommit: 是否自动提交
  public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
    return new JdbcTransaction(ds, level, autoCommit);
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.2 调度器Executor的创建

Executor是SqlSession的核心,其select update commit rollback close等方法均由Executor代理实现。Executor代表调度器,由他来调度StatementHandler ParameterHandler ResultSetHandler。四者合称mybatis运行时四大组件。四大组件均可由用户通过插件注入,也都有默认实现。下面看创建Executor的源码

// 创建sqlsession执行器Executor
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
  // executorType通过settings节点中的defaultExecutorType来设置,没有设置则默认为SIMPLE
  executorType = executorType == null ? defaultExecutorType : executorType;
  executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
  Executor executor;

  // 根据executorType分别创建BatchExecutor ReuseExecutor SimpleExecutor
  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包装下之前创建的executor,简单理解就是为executor添加了cache功能
  if (cacheEnabled) {
    executor = new CachingExecutor(executor);
  }

  // 将执行器executor设置到plugins节点中设置的所有插件中,作为插件的目标执行器。
  executor = (Executor) interceptorChain.pluginAll(executor);
  return executor;
}

public Object pluginAll(Object target) {
    // 遍历所有插件,将传入的target,作为插件的目标执行器。插件通过配置XML文件的plugins节点设置。
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

Executor根据executorType分别创建BatchExecutor ReuseExecutor SimpleExecutor三个实现类,他们的基类为BaseExecutor。下一节我们分析selectList方法时,以SimpleExecutor这个默认的调度器为例分析。

2.3 SqlSession实例的创建

SqlSession的默认实现为DefaultSqlSession,其创建十分简单,构造方法如下

public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
  this.configuration = configuration;
  this.executor = executor;
  this.dirty = false;
  this.autoCommit = autoCommit;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

其中executor成员最为关键,DefaultSqlSession的大部分方法均是通过它来代理实现。比如select update方法。而delete和insert方法均调用update方法来实现。

// select方法通过executor实现,典型的代理模式
// selectOne selectList均调用它实现
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
  try {
    MappedStatement ms = configuration.getMappedStatement(statement);
    // 利用调度器Executor代理实现
    executor.query(ms, wrapCollection(parameter), rowBounds, handler);
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}

// update方法通过executor实现,典型的代理模式
// insert update等DML操作均调用它实现 
public int update(String statement, Object parameter) {
    try {
      dirty = true;
      MappedStatement ms = configuration.getMappedStatement(statement);
      // 利用调度器Executor代理实现
      return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

public int insert(String statement, Object parameter) {
    return update(statement, parameter);
}

public int delete(String statement, Object parameter) {
    return update(statement, parameter);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

3 总结

构建SqlSession的核心是创建调度器Executor,它是mybatis运行的核心。通过调度StatementHandler ParameterHandler ResultSetHandler来完成各种操作。四者合称SqlSession四大组件。后面一节我们以sqlSession.selectOne()方法为例来分析mybatis的CRUD操作的背后原理。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325687014&siteId=291194637
Recommended