mybatis源碼解析-獲取Sqlsession

上篇文章講了mybatis是怎麼創建SqlSessionFactory的:mybatis源碼解析-SqlsessionFactory,簡單來說就是通過構造模式讀取xml配置文件封裝到Configuration對象中,返回一個默認的DefaultSqlSessionFactory對象,需要注意的是我們寫的每一個mapper映射文件在配置類中定義好了之後會被解析進Configuration中,並且mapper映射文件中的增刪改查標籤都有與之對應的MappedStatement對象封裝,我們還是擺出hello world來演示:

//1.通過輸入流解析xml配置文件
InputStream inputstream = Resources.getResourceAsStream("xxx.xml")
SqlsessionFactory sqlsessionfactory = new SqlsessionFactoryBuilder().build(inputstream);
//2.獲取和數據庫的鏈接,創建會話
SqlSession openSession = sqlsessionfactory.openSession();
//3.獲取接口的實現類對象,會爲接口自動的創建一個代理對象mapper,代理對象會去執行增刪改查方法
xxxMapper mapper = openSession.getMapper(xxxMapper.class)
//4.執行增刪改的方法

第一步已經講過了,現在來看第二步,獲取鏈接創建會話SqlSession

Sqlsession

1.1:直接來到sqlsessionfactory.openSession();這個方法,它其實調用的是DefaultSqlSessionFactoryopenSessionFromDataSource方法

public SqlSession openSession(boolean autoCommit) {
        return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, autoCommit);
    }

在進入查看這個方法之前,this.configuration.getDefaultExecutorType()這個是選擇一種執行器在這裏插入圖片描述
這裏默認選的是SIMPLE,在mybatis官方文檔有這樣的三種設置:在這裏插入圖片描述

1.2:好了,進入openSessionFromDataSource這個方法:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var12) {
            this.closeTransaction(tx);
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }

首先根據configuration獲取當前環境,配置事務信息,Executor executor = this.configuration.newExecutor(tx, execType);這裏根據我們選擇的執行器類型創建執行器,進入newExecutor方法:

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        executorType = executorType == null ? this.defaultExecutorType : executorType;
        executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
        Object 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 (this.cacheEnabled) {
            executor = new CachingExecutor((Executor)executor);
        }

        Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
        return executor;
    }

那麼什麼是Executor呢?請往下看:
在這裏插入圖片描述
這個接口裏的方法就是我們執行增刪改查的方法,我們繼續走,在newExecutor方法中有這樣一段代碼:

if (this.cacheEnabled) {
            executor = new CachingExecutor((Executor)executor);
        }

它的意思是判斷cacheEnabled是否開啓也就是我們configuration全局配置中是否開啓二級緩存,如果開啓就用CachingExecutor((Executor)executor)來包裝這個執行器,我們進入這個類:
1.3:我們截取一部分代碼來研究:

public class CachingExecutor implements Executor {
    private final Executor delegate;
    private final TransactionalCacheManager tcm = new TransactionalCacheManager();

    public CachingExecutor(Executor delegate) {
        this.delegate = delegate;
        delegate.setExecutorWrapper(this);
    }

來看一看這個類的結構:、
在這裏插入圖片描述
我們可以知道,這個類將傳進來的執行器包裝了一下,真正執行增刪改查的是他內部的Executor delegate對象,我們繼續看newExecutor在最終完成並返回Executor前,還會調用這個方法:
Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
就是調用攔截器鏈的pluginAll方法,在目前爲止這個方法看起來貌似沒什麼作用,其實不然,在後面的插件介紹中,它就通過這種方式來包裝我們的執行器,我們來看一下這個方法:

public Object pluginAll(Object target) {
        Interceptor interceptor;
        for(Iterator var2 = this.interceptors.iterator(); var2.hasNext(); target = interceptor.plugin(target)) {
            interceptor = (Interceptor)var2.next();
        }

        return target;
    }

很簡單,調用所有的攔截器來對Executor進行封裝,好了,到現在我們就把Executor封裝完畢了,回到1.2openSessionFromDataSource這個方法:

Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
return var8;

executor傳入了DefaultSqlSession中,來看一下這個類:
在這裏插入圖片描述
最終返回了DefaultSqlSession

總結

最後用一張圖來簡單回顧一下:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章