Executor是MyBatis四大核心對象之一馋嗜,是MyBatis 調(diào)度的核心,負(fù)責(zé)數(shù)據(jù)庫的操作和查詢緩存的維護辩稽,實際應(yīng)用中涉及的SqlSession接口的功能都是基于Executor調(diào)度StatementHandler惧笛、ParameterHandler、ResultSetHandler實現(xiàn)的逞泄。
1.Executor繼承體系
如上圖所示患整,位于繼承體系最頂層的是 Executor 執(zhí)行器接口拜效,它有兩個實現(xiàn)類,分別是BaseExecutor和?CachingExecutor各谚。
BaseExecutor?是一個抽象類紧憾,這種通過抽象的實現(xiàn)接口的方式是適配器設(shè)計模式之接口適配?的體現(xiàn),是Executor 的默認(rèn)實現(xiàn)昌渤,實現(xiàn)了大部分 Executor 接口定義的功能赴穗,降低了接口實現(xiàn)的難度。BaseExecutor 的子類有三個膀息,分別是 SimpleExecutor般眉、ReuseExecutor 和 BatchExecutor。
SimpleExecutor?: 簡單執(zhí)行器潜支,是 MyBatis 中默認(rèn)使用的執(zhí)行器甸赃,每執(zhí)行一次 update 或 select,就開啟一個Statement 對象毁腿,用完就直接關(guān)閉 Statement 對象(可以是 Statement 或者是 PreparedStatment 對象)
ReuseExecutor?: 可重用執(zhí)行器辑奈,這里的重用指的是重復(fù)使用 Statement,它會在內(nèi)部使用一個 Map 把創(chuàng)建的Statement 都緩存起來已烤,每次執(zhí)行 SQL 命令的時候,都會去判斷是否存在基于該 SQL 的 Statement 對象妓羊,如果存在 Statement 對象并且對應(yīng)的 connection 還沒有關(guān)閉的情況下就繼續(xù)使用之前的 Statement 對象胯究,并將其緩存起來。因為每一個 SqlSession 都有一個新的 Executor 對象躁绸,所以我們緩存在 ReuseExecutor 上的 Statement作用域是同一個 SqlSession裕循。
BatchExecutor?: 批處理執(zhí)行器,用于將多個 SQL 一次性輸出到數(shù)據(jù)庫
CachingExecutor: 緩存執(zhí)行器净刮,先從緩存中查詢結(jié)果剥哑,如果存在就返回之前的結(jié)果;如果不存在淹父,再委托給Executor delegate 去數(shù)據(jù)庫中取株婴,delegate 可以是上面任何一個執(zhí)行器。
2.Executor 的創(chuàng)建和選擇
我們上面提到?Executor?是由 Configuration 創(chuàng)建的暑认,Configuration 會根據(jù)執(zhí)行器的類型創(chuàng)建困介,如下
這一步就是執(zhí)行器的創(chuàng)建過程,根據(jù)傳入的?ExecutorType?類型來判斷是哪種執(zhí)行器蘸际,如果不指定 ExecutorType 座哩,默認(rèn)創(chuàng)建的是簡單執(zhí)行器。它的賦值可以通過兩個地方進行賦值:
可以通過<settings>標(biāo)簽來設(shè)置當(dāng)前工程中所有的 SqlSession 對象使用默認(rèn)的 Executor
另外一種直接通過Java對方法賦值的方式
SqlSession sqlSession = factory.openSession(ExecutorType.SIMPLE);
3.Executor 的具體執(zhí)行過程
我們以 SqlSesion的selectList?為例粮彤,它會調(diào)用到?executor.query?方法根穷。
當(dāng)有一個查詢請求訪問的時候姜骡,首先會經(jīng)過 Executor 的實現(xiàn)類?CachingExecutor,先從緩存中查詢 SQL 是否是第一次執(zhí)行屿良,如果是第一次執(zhí)行的話圈澈,那么就直接執(zhí)行 SQL 語句,并創(chuàng)建緩存管引,如果第二次訪問相同的 SQL 語句的話士败,那么就會直接從緩存中提取。
上面這段代碼是從 selectList -> 從緩存中 query 的具體過程褥伴,如果二級緩存為空谅将,則由委托的Executor進行查詢。
Executor采用模板方法設(shè)計模式重慢,最終的執(zhí)行是由BaseExecutor的子類的doQuery方法進行執(zhí)行饥臂,到這里Executor所做的工作就完事了,后面交給StatementHandler繼續(xù)執(zhí)行似踱。后面《mybatis深度歷險》洗了的文章會介紹StatementHandler隅熙。