结构图

mybatis核心组件之间的关系可以用下图表示:

其中类名前加个”I“表示接口

sqlSession 生命周期_sqlSession 生命周期

SqlSessionFactoryBuilder

从图上可以看到,除了Configuration外,每个类的类名都包含一个”SqlSession“,从结构图中也可以看到,我们最终的目标就是为了创建SqlSession,SqlSession可以暂时理解为jdbc中的Connection,通过SqlSession执行sql。

SqlSessionFactoryBuilder顾名思义,是SqlSessionFactory的构建器。

sqlSession 生命周期_sqlSession 生命周期_02

 SqlSession唯一的职责就是构建SqlSessionFactory。构建方式也是多种多样的,可以传入配置文件的Reader对象、输入流,或者直接传入一个封装好的配置类。

Configuration

Configuration类在上面的SqlSessionFactoryBuilder中就已经露面了,这个类中有很多配置项。

这些配置项在启动的时候,会一次性初始化好。(或通过代码、或通过配置文件)

可以看下Configuration与SqlSessionFactory的关系。

sqlSession 生命周期_数据源_03

 (DefaultSqlSessionFactory是SqlSessionFactory的一个实现类,后面会说到)

DefaultSqlSessionFactory的构造函数只有一个,Configuration作为配置类是必传的。SqlSessionFactory通常与数据源相对应,一个数据源只有一个Factory实例,所以Configuration也同样会常驻内存。

回想初遇mybatis,还没有用上springboot时,常常需要维护一个xml配置文件。

sqlSession 生命周期_sqlSession 生命周期_04

这个配置文件的所有配置项都与Configuration一 一对应。

SqlSessionFactory

SqlSessionFactory是一个接口,有两个实现类SqlSessionManager与DefaultSqlSessionFactory。

职责单一,仅仅用来创建SqlSession。

public interface SqlSessionFactory {

  //8个方法可以用来创建SqlSession实例
  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();

}

创建过程:

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);
      //然后产生一个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 生命周期_配置文件_05

数据连接对象(Connection)可以没有,因为可以从数据源中获取。

所以我们可以看到,mybatis从配置类中获取到了Environment对象,并拿到了数据源。

2、生成执行器

得到事务对象后,包装一下就成了Executor(执行器)。

Executor负责sql最终的执行。

3、创建SqlSession

SqlSession

终于到主角了,SqlSession。

SqlSession也是接口,只有两个实现类,SqlSessionManager以及DefaultSessionManager。

比较常用的是DefaultSessionManager。

 其实从上面的创建过程就可以看出SqlSession的主要成分了。

new DefaultSqlSession(configuration, executor, autoCommit);

配置类、执行器,最后一个参数表示是否自动提交事务。

意图相当明显了,这分明是让SqlSession做最关键的活——调用executor执行sql语句。

sql语句哪里来?

sqlSession 生命周期_sql_06

SqlSession开放的方法接口可以看出,mybatis把常见的一些数据库操作做了封装,不出意外SqlSession就是接待sql的窗口。

我们写一个sql

public interface RoleMapper {
    public Role getRole(@Param("id") Long id);
}

对应的xml

<select id="getRole" parameterType="long" resultMap="roleMap">
        select
        id,role_name as roleName,note from role where id=#{id}
</select>

 最终会调用SqlSession的第二个方法

<T> T selectOne(String statement, Object parameter);

 statement并不是指最终的sql,而是与mybatis中的mapper的方法相对应(mapper接口)。

第二参数通常是map或者pojo对象。比如上述案例中虽然传递只有一个参数id,mybatis也会封装成一个map。见下图:

sqlSession 生命周期_sqlSession 生命周期_07

 通过mapper的方法名找到MappedStatement,并交给执行器executor执行sql。

sqlSession 生命周期_sql_08

这一篇算是总览,后面会根据一些具体的实现再做总结。

如有错误,欢迎批评指正!