Mybatis源码--Sql执行分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ONROAD0612/article/details/83586852

1 概述

前面我们分析了一些Sql解析过程中的一些重要类(Executor、StatementHandler等)的源码,现在就需要对将这些类串起来的流程进行一个详细的分析,所以我们现在来分析一下Mybatis中Sql执行的流程。

2 流程图

从流程图我们大致将Sql执行分成四步,针对第一步在前面的文章中我们已经有过分析,所以现在我们就对后面三步进行深入分析。

3 流程分析

在这里我们首先上一段测试代码,这样方便结合上面的流程图进行理解。

  String resource = "mybatis-config.xml";
  InputStream is = Resources.getResourceAsStream(resource);
  SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
  SqlSession session = sqlSessionFactory.openSession();
  UserMapper userMapper = session.getMapper(UserMapper.class);
  User user = userMapper.findUserInfo("liubei");

我们首先来看第二步,调用openSession函数获得SqlSession。

3.1 获取SqlSession

在这里实际上是调用的SqlSessionFactory的实现类DefaultSqlSessionFactory的openSession函数。

  @Override
  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

这个方法里面直接调用openSessionFromDataSource函数来生成SqlSession。

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);

      //生成并返回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();
    }
  }

针对上面的逻辑,我们来具体看看每步做了什么。

(1)获取环境对象

public Environment getEnvironment() {
    return environment;
  }

这里直接将读取配置文件初始化Configuration的时候生成的Environment进行返回就行了。

(2)获取事务工厂

private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
    
    //获取事务工厂
    if (environment == null || environment.getTransactionFactory() == null) {
      return new ManagedTransactionFactory();
    }
    return environment.getTransactionFactory();
  }

针对事务工厂这里简单说明一下,我会用另外的博文对Mybaits事务处理这一块内容进行详细说明。

Mybatis的事务处理这里的设计使用了抽象工厂的设计模式。拥有两种事务工厂,ManagedTransactionFactory和JdbcTransactionFactory。可想而知,这两种事务工厂分别生成ManagedTransaction和JdbcTransaction两种事务处理类型。ManagedTransaction将事务处理交给程序的容器如(JBOSS,Weblogic),而JdbcTransaction则由JDBC来处理事务。

这里如果Mybatis配置文件中没有指定事务的类型,则使用ManagedTransactionFactory,如果指定为“JDBC”,则使用JdbcTransactionFactory。

(3)生成事务

这里就不进行详细说明了,可想而知这里其实就行对事务Transaction的基础内容进行设置,例如Connection、TransactionIsolationLevel。

(4)获取执行器

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;
  }
所有的Mybatis语句都是通过执行器来完成的,所以这一步相当重要。

(5)生成并返回SqlSession

这一步其实就是调用构造函数DefaultSqlSession来生成SqlSession。

public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
    this.configuration = configuration;
    this.executor = executor;
    this.dirty = false;
    this.autoCommit = autoCommit;
  }

3.2 获取Mapper接口的动态代理对象

这里我们直接从DefaultSqlSession的getMapper函数开始查看。

  @Override
  public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
  }

可以看见,这里实际上调用的是Configuration的getMapper函数。

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

而这个函数又是调用的MapperRegistry的getMapper函数,看来动态代理就是在MapperRegistry的getMapper函数中可以看见啊。

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {

    //获取到mapper代理工厂
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {

      //获得并返回代理对象
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

前面的文章我们提到过MapperProxyFactory的作用其实就是生成Mapper接口的动态代理对象。

猜你喜欢

转载自blog.csdn.net/ONROAD0612/article/details/83586852