Mybatis源码分析(二)SqlSession和Excutor

2022-10-08  本文已影响0人  小尾巴1024

导读

上一篇文章介绍了Mybatis是怎样读取并解析mybatis-config.xml和xxxMapper.xml等xml信息并封装到Configuration对象中。这一篇文章主要介绍Mybatis的主要对象SqlSession和事务是怎样管理和执行的。带着两个疑问:1. 构造好的Configuration对象是在哪里用的?2. SqlSession又是怎样创建的?

一、使用Configuration对象:

回到XMLConfigBuilder的parse方法中,这个方法调用了一个主要方法parseConfiguration()解析完xml配置文件之后,返回一个configuration对象,如下

    public Configuration parse() {
        if (this.parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        } else {
            this.parsed = true;
            // 主要方法,解析xml标签等配置信息放到configuration中
            this.parseConfiguration(this.parser.evalNode("/configuration"));
            //返回configuration对象
            return this.configuration;
        }
    }
build(parser.parse());

这个build方法就是传入一个Configuration对象,然后构建一个DefaultSqlSession对象。

public SqlSessionFactory build(Configuration config) {
  return new DefaultSqlSessionFactory(config);
}

到些SqlSession对象就构建出来了

配置文件解析流程

解析配置文件.png
获取到SqlSessionFactory之后 ,就可以创建SqlSession了。

二、构建SqlSession:

从前面的配置文件解析流程我们知道,得到的sqlSessionFactory是DefaultSqlSessionFactory类型

sqlSession = sqlSessionFactory.openSession();

所以上面调用的openSession()方法为DefaultSqlSessionFactory中的方法。

public class DefaultSqlSessionFactory implements SqlSessionFactory {
  //配置文件所有内容
  private final Configuration configuration;
  //创建session
  @Override
  public SqlSession openSession() {
    //调用的是另外一个openSessionFromDataSource方法
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }
  //其实是调用这个方法
  //protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      //对应xml标签<environments> ,这个在配置文件解析的时候就已经存放到configuration中了。
      final Environment environment = configuration.getEnvironment();
      //构建事务工厂
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      //构建一个事务对象  
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //创建一个executor来执行SQL  
      final Executor executor = configuration.newExecutor(tx, execType);
      //创建一个DefaultSqlSession对象并返回
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); 
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
  
    private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
    if (environment == null || environment.getTransactionFactory() == null) {
      return new ManagedTransactionFactory();
    }
    return environment.getTransactionFactory();
  }

创建事务Transation:

 tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

TransactionFactory有两个子类,如下:


TransactionFactory类图.png

事务工厂类型可以配置为JDBC类型或者MANAGED类型。

如果我们配置的是MANAGED,会把事务交给容器来管理,比如JBOSS,Tomcat。因为我们是本地跑的程序,如果配置成MANAGED就会不有任何事务。
但是,如果是Spring+Mybatis,则没有必要配置,因为我们会直接在applicationContext.xml里配置数据源和事务管理器,从而覆盖Mybatis的配置。

三、创建Executor

// 把事务传给newExecutor()方法创建执行器Executor对象。
configuration.newExecutor(tx, execType)

// 调用configuration的newExecutor方法创建Executor。

final Executor executor = configuration.newExecutor(tx, execType);
//Configuration中
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    //第一步
    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);
    }
    //第二步
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    //第三步
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

创建Excutor的过程分为三步:
第一步:创建执行器
Executor的基本类型有三种:SIMPLE为默认类型。

public enum ExecutorType {
    SIMPLE, REUSE, BATCH
}

Mybatis Excutor类图:

Mybatis Excutor类图.png
提问:为什么要让抽象类BaseExecutor实现Executor接口,然后让具体实现类继承抽象类呢?
这就是模板方法模式的实现。

模板方法模式就是定义一个算法骨架,并允许子类为一个或者多个步骤提供实现。模板方法是得子类可以再不改变算法结构的情况下,重新定义算法的某些步骤。
抽象方法是在子类汇总实现的,每种执行器自己实现自己的逻辑,BaseExecutor最终会调用到具体的子类。

抽象方法:

protected abstract int doUpdate(MappedStatement var1, Object var2) throws SQLException;
protected abstract List<BatchResult> doFlushStatements(boolean var1) throws SQLException;
protected abstract <E> List<E> doQuery(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, BoundSql var5) throws SQLException;
protected abstract <E> Cursor<E> doQueryCursor(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4) throws SQLException;

第二步:缓存装饰

if (cacheEnabled) {
  executor = new CachingExecutor(executor);
}

如果cacheEnabled=true,会用装饰器设计模式对Executor进行装饰。
第三步:插件代理

executor = (Executor) interceptorChain.pluginAll(executor);

到此,执行器创建的就搞定了。
Executor创建完毕后,就该创建DefaultSqlSession了,如下:

//创建一个DefaultSqlSession对象并返回
return new DefaultSqlSession(configuration, executor, autoCommit);

进入DefaultSqlSession的构造方法:

public class DefaultSqlSession implements SqlSession {
   private final Configuration configuration;
   private final Executor executor;
   public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
     this.configuration = configuration;
     this.executor = executor;
     this.dirty = false;
     this.autoCommit = autoCommit;
   }
}

DefaultSqlSession中包含两个重要属性:configuration和executor

到此,SqlSession对象构建完毕。

sqlSession = sqlSessionFactory.openSession();
// 这里的sqlSession其实就是DefaultSqlSession:
// sqlSession = new DefaultSqlSession();

构建SqlSession过程如下图:


构建SqlSession.png

参照文档: mybatis官网-配置腾讯云博客

上一篇下一篇

猜你喜欢

热点阅读