美文网首页
Mybatis源码分析(二)SqlSession和Excutor

Mybatis源码分析(二)SqlSession和Excutor

作者: 小尾巴1024 | 来源:发表于2022-10-08 20:23 被阅读0次

    导读

    上一篇文章介绍了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类型。

    • JdbcTransactionFactory生产JdbcTransaction。
    • ManagedTransactionFactory生产ManagedTransaction。

    如果我们配置的是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

    • configuration 存放配置信息
    • executor 执行器

    到此,SqlSession对象构建完毕。

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

    构建SqlSession过程如下图:


    构建SqlSession.png

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

    相关文章

      网友评论

          本文标题:Mybatis源码分析(二)SqlSession和Excutor

          本文链接:https://www.haomeiwen.com/subject/juyenrtx.html