天天看點

Mybatis3.x 源碼閱讀-03擷取SqlSession1. 前言2. 正文3. 總結4. 參考

1. 前言

上篇說到,建構了DefaultSqlSessionFactory,這一節,繼續一探究竟。

2. 正文

老規矩,先上案例。

2.1 案例

@Test
    public void test(){
        SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();@1
        PersonDao personDao =  sqlSession.getMapper(PersonDao.class);
        Person p = new Person();
        p.setAddress("廣東省");
        p.setAge(12);
        p.setEmail("[email protected]");
        p.setName("chen");
        p.setPhone("15345634565");
        personDao.insert(p);@4
        System.out.println(p.toString());
        sqlSession.commit();
        sqlSession.close();
    }
           

@1根據得到的SqlSessionFactory ,打開一個session,下面一起進入到裡面,看下裡面具體的邏輯

2.2 DefaultSqlSessionFactory#openSession

DefaultSqlSessionFactory#openSession

@Override
  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }
  
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);@1
      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();
    }
  }
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
    if (environment == null || environment.getTransactionFactory() == null) {
      return new ManagedTransactionFactory();
    }
    return environment.getTransactionFactory();
  }
           

首先,這裡設定了預設的執行器類型:configuration.getDefaultExecutorType(),事務隔離級别傳入了null。

@1 TransactionFactory是接口,有2個實作類,分别是JdbcTransactionFactory、ManagedTransactionFactory,根據目前環境,擷取事務管理工廠,如果環境為空或者沒有配置事務工廠,則用預設的ManagedTransactionFactory,否則就調用你mybatis-config.xml中配置的,我這裡配置了JDBC,并且在解析的時候,已經set到Environment中了,是以,直接調用environment.getTransactionFactory()就可以擷取到了。下面介紹下這2中類型的差別

Mybatis3.x 源碼閱讀-03擷取SqlSession1. 前言2. 正文3. 總結4. 參考

2.3 JdbcTransaction和ManagedTransaction的差別

到這裡,是不是先看下這2個事務工廠的差別。這裡的差別,主要是JdbcTransaction和ManagedTransaction的差別, 這2個類都實作了Transaction接口,接口了定義了幾個方法,大家經常見到這幾個。

Mybatis3.x 源碼閱讀-03擷取SqlSession1. 前言2. 正文3. 總結4. 參考

Mybatis管理事務是分為兩種方式:

(1)使用JDBC的事務管理機制,就是利用java.sql.Connection對象完成對事務的送出

(2)使用MANAGED的事務管理機制,這種機制mybatis自身不會去實作事務管理,而是讓程式的容器(JBOSS,WebLogic)來實作對事務的管理

仔細看:

ManagedTransaction#commit、rollback、getTimeout都是空的。隻負責打開和關閉連接配接。

其實,JDBC 是mybatis 幫我們實作了事務管理,當然這個活,也可以交由其它程式的容器(JBOSS,Weblogic)來實作。

繼續回到DefaultSqlSession#openSessionFromDataSource中

final Executor executor = configuration.newExecutor(tx, execType);

execType 是前面傳入的預設的執行器類型,即ExecutorType.SIMPLE。

下一步,進newExecutor 方法

2.4 Configuration#newExecutor

mybatis的執行器有三種類型:

ExecutorType.SIMPLE 這個類型不做特殊的事情,它隻為每個語句建立一個PreparedStatement。

ExecutorType.REUSE 這種類型将重複使用PreparedStatements。

ExecutorType.BATCH 這個類型批量更新,且必要地差別開其中的select 語句,確定動作易于了解。

Configuration#newExecutor

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);@1
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);@2
    return executor;
  }

           

InterceptorChain#pluginAll

public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }
           

根據executorType不同的類型,建構相應的執行器,但cacheEnabled 預設是true,是以,這裡傳回CachingExecutor執行器

@2 從配置插件裡面取出插件對象(通過jdk動态代理來擷取對象),mybatis裡插件用到了責任鍊的設計模式。

繼續傳回DefaultSqlSessionFactory#openSessionFromDataSource 方法

得到了執行器,直接new 一個DefaultSqlSession,接着來看下DefaultSqlSession ,構造函數的參數有配置、執行器、dirty(false 表示記憶體中的資料和資料庫中一緻), 是否自動送出=false參數。

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

裡面有常用的一些查詢方法

Mybatis3.x 源碼閱讀-03擷取SqlSession1. 前言2. 正文3. 總結4. 參考

到這裡,我們就擷取到Session, 下一篇,重點介紹裡面的重要方法。

3. 總結

3.1 通過上面的功能,我們擷取到了session,session是我們與資料庫溝通的橋梁

3.2 通過session 可以擷取到系統中的mapper 代理對象,下一篇就是介紹如何擷取的。

4. 參考

[1] https://blog.csdn.net/meiwen1111/article/details/8260387

[2] https://blog.csdn.net/qq_36074042/article/details/74206611