mybatis(一) sqlSessionFactory和sqlSession的创建

最近想深入学习一下mybatis,想通过看mybatis的源码,了解mybatis的整个工作流程,熟悉mybatis的各种细节。

使用mybatis的方式不同,sqlSessionFactory的创建方法也不同,具体可以看SqlSessionFactoryBuilder的源代码,里面有很多重载的build方法。本文是在SpringBoot环境下,基于mapper接口使用mybatis,在启动项目中的某个时间点会调用SqlSessionFactoryBuilder中的如下方法创建SqlSessionFactory:

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

这个方法需要一个Configuration类型的参数,所以需要先创建Configuration对象,虽然不同的build方法实现有不同,但是核心都是解析mybatis.xml配置文件和mapper.xml的配置文件。

 创建完sqlSessionFactory后,在具体执行增删改查的时候,还需要创建sqlSession

在使用mapper接口增删改查的方式中,sqlSession的创建是在执行增删改查的过程中,在sqlSession的代理方法中创建的。

如下:sqlSessionTemplate会调用sqlSessionProxy的一个代理方法

public <E> List<E> selectList(String statement, Object parameter) {
  return this.sqlSessionProxy.<E> selectList(statement, parameter);
}

sqlSessionProxy的创建方法如下,所以会调用SqlSessionInterceptor中的invoke方法

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
    PersistenceExceptionTranslator exceptionTranslator) {

  notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
  notNull(executorType, "Property 'executorType' is required");

  this.sqlSessionFactory = sqlSessionFactory;
  this.executorType = executorType;
  this.exceptionTranslator = exceptionTranslator;
  this.sqlSessionProxy = (SqlSession) newProxyInstance(
      SqlSessionFactory.class.getClassLoader(),
      new Class[] { SqlSession.class },
      new SqlSessionInterceptor());
}

SqlSessionInterceptor是SqlSessionTemplate中的一个private内部类, invoke方法中调用了

SqlSessionUtils.getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator)

  (由于直接导入了静态方法,所以调用的时候没有在方法前面加上类名,import static org.mybatis.spring.SqlSessionUtils.getSqlSession;)

private class SqlSessionInterceptor implements InvocationHandler {
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    SqlSession sqlSession = getSqlSession(
        SqlSessionTemplate.this.sqlSessionFactory,
        SqlSessionTemplate.this.executorType,
        SqlSessionTemplate.this.exceptionTranslator);
    try {
      Object result = method.invoke(sqlSession, args);
      if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
        // force commit even on non-dirty sessions because some databases require
        // a commit/rollback before calling close()
        sqlSession.commit(true);
      }
      return result;
    } catch (Throwable t) {
      Throwable unwrapped = unwrapThrowable(t);
      if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
        // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
        closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        sqlSession = null;
        Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
        if (translated != null) {
          unwrapped = translated;
        }
      }
      throw unwrapped;
    } finally {
      if (sqlSession != null) {
        closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
      }
    }
  }
} sqlSessionUtils.getSqlSession()后面的时序图如下:

在DefaultSqlSessionFactory的openSessionFromDataSource方法中,用 configuration.newExecutor(tx, execType)

创建了mybatis四大对象之一的executor对象,在执行增删改查的时候需要用到executor

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

newExecutor方法如下,executor = (Executor) interceptorChain.pluginAll(executor),这段代码将executor封装成了拦截器链,是mybati的executor插件的原理。

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

猜你喜欢

转载自blog.csdn.net/qq_38478903/article/details/84728924
今日推荐