深入理解mybatis
Mybatis元件時序圖
SqlSessionFactoryBuilder類通過讀取Configuration.xml檔案的配置呼叫build()方法生成SqlSessionFactory物件。集成了spring的話,spring容器在啟動的時候會就會載入好SqlSessionFacotry這物件也是呼叫這個類build()的方法。
SqlSession是當一個請求進來的時候SqlSessionFactory會通過openSession方法建立一個新的例項物件sqlSession
一、配置
Configuration這是一個配置物件,存放的是Configuration.xml裡面的我們對於mybatis的一些配置,專案初始化的時候載入 Environment是一個數據源配置配置物件,也是配置在Configuration.xml裡面的Environment標籤。專案初始化的時候就載入好了(我們用的是alibaba的druid資料來源)
二、事務
結合圖openSession方法其中的TransactionFactory是mybatis的事務管理(工廠模式) mybatis的本身事務管理機制分成兩種 1、使用JDBC事務管理機,這種機制會生成一個JdbcTransaction物件有。也就是呼叫java.sql.Connection來進行管理 2、使用容器的管理機制也就是ManagedTransaction這個物件來管理事務。這種方式程式本身是不會去 管理事務了,即使在程式中執行了commit和rollback也沒用。因為程式本身不對事務進行管理了。這個事務管理交給容器 如果mybatis集成了spring 而是使用org.mybatis.spring包裡面的SpringManagedTransaction來進行管理(spring容器進行事務管理)
三、sqlSession和Executor執行器
sqlSession預設實現類defaultSqlSession, 在這個物件中它執有configuration物件和executor物件。
configuration物件就是我們上面提到的一個配置對像,根據Configuration.xml配置檔案而來的一個物件
檢視DefaultSqlSession的原始碼,可以發現它所有的操作都通過executor物件在呼叫。其實sqlSession就像只是對外暴露的一個介面,而真正對資料的互動是由executor來進行操作的。sqlSession其實只是對Executor一個包裝。
而Executor才是真正的工作者。Executor的實現類分別是以下三種,以下是它們的區別和它們的關係圖 1.SimpleExecutor是mybatis預設的實現類。它的特性是每對資料進行一次互動會關閉掉statement 2.ReuseExecutor會對statement進行重複使用。對資料庫操作執行完成之後會把statement放在一個map裡面,key是執行的sql,value就是本次執行的statement物件。如果本次會話再次對資料進行操作。
那麼這個執行器會根據sql去呼叫這個map裡面statement去執行沒有則建立並存放到map裡同。而不是重新去例項化一個新的statement物件。
3.BatchExecutor支援批量操作
注:statement 就是java自帶的jdbc的資料操作物件
以下是它們之間的類圖(策略模式)
四、快取
CachingExexutor是mybatis二級快取機制的體現,它也實現了Executor這個介面 (裝飾者模式),
mybatis快取機制分一級快取和二級快取,
1.一級快取是session會話級,一次會話建立一個快取物件這個快取物件在本次會話是共享的,會話結束快取物件也就銷燬了,一次SqlSession會建立一個executor物件。executor物件會執有一個PerpetualCahce快取物件。
這個快取物件會將本次的查詢結果集放到一個map的value裡面。key是根據statementId、sql、param生成
2.二級快取是application級別,所有會話都可以對這個快取物件進行操作的。這個快取是共享的。這個快取級別粒度非常細。在開發過種中開發者可以自定義快取實現方式,需要實現Cache介面。需要在maaper檔案裡面配置通過cache標籤配置快取。
也可以通過cach-ref標籤引入別一個mapper裡面定義的快取
注:mybatis是快取機制是先呼叫 二級快取,如果不存在再去呼叫一級快取。如果一級快取也不存在。才會去資料庫查。
先看看SimpleExecutor執行器對一個數據庫查詢語句是怎麼去實現的資料庫查詢的。首先它會建立一個jdbc statement物件
引數:
MappedStatement:mapper檔案裡面sql配置資訊
object parameter: 動態sql語句的引數
RowBounds: mybais自帶的分頁功能
ResultHandler: sql語句返回的結果集處理器,比如我們mapper檔案裡面配置 resultMap , resultType結果集的處理
BoundSql: sql語句及一些sql的簡單資訊,比如sql用幾個 ?佔位符,幾個引數等一些資訊。
五、StatementHandler處理器
以下是StatementHandler類圖(策略模式)
StatementHandler預設實現類是RoutingStatementHandler,以下是它的構造方法
statementType是配置在mapper.xml檔案sql語句標籤上的。 不寫的話預設是PREPARED
這三個StatementHandler。 分別是 statement、PreparedStatement、CallableStatement
SimpleStatementHandler
PreparedStatementHandler
CallableStatementHandler
以下是它們的區別
1、Statement每次執行sql語句,資料庫都要執行sql語句的編譯,最好用於僅執行一次查詢並返回結果的情形,效率高於PreparedStatement.
注:根據這個statement特性。如果一條sql語句使用了這個statement來進行資料操作。那麼mybatis的SimpleStatementHandler是不會對引數進行處理的。它會預設認為你這條sql是沒有引數的。不會呼叫mybatis的ParamerHandler來進行引數處理
2、PreparedStatement是預編譯的,使用PreparedStatement有幾個好處(mybatis預設是使用這個)
a.在執行可變引數的一條SQL時,PreparedStatement比Statement的效率高,因為DBMS預編譯一條SQL當然會比多次編譯一條SQL的效率要高。
b.安全性好,有效防止Sql注入等問題。
c.對於多次重複執行的語句,使用PreparedStament效率會更高一點,並且在這種情況下也比較適合使用batch;
d.程式碼的可讀性和可維護性。
-
3、CallableStatement介面擴充套件PreparedStatement,用來呼叫儲存過程,它提供了對輸出和輸入/輸出引數的支援。CallableStatement介面還具有對PreparedStatement介面提供的輸入引數的支援。
六、ParamerHandler引數處理
ParamerHandler的實現類只有一個DefaultParamerHandler,它的主要作用是對引數進行處理。基中mybatis $ 和 # 這兩個符號的處理方式不一樣。
$符號處理方式: 會將值直接附到sql上面去,進行預編譯,存在sql注入功擊。當你不確認這個$符號繫結的那個物件的值時 , 慎用!!!
#符號處理方式:會採用 ?這個佔位符進行預編譯。較為安全
七、ResultSetHandler結果集處理
ResultSetHandler的主要功能是對結果集返回的一個封裝。
SqlSession物件
有狀態:有狀態就是有資料儲存功能。有狀態物件(Stateful Bean),就是有例項變數的物件 ,可以儲存資料,是非執行緒安全的。在不同方法呼叫間不保留任何狀態。
無狀態:無狀態就是一次操作,不能儲存資料。無狀態物件(Stateless Bean),就是沒有例項變數的物件 .不能儲存資料,是不變類,是執行緒安全的。
因為mybatis的sqlSesssion 執有Exector物件。所以他是一個有狀態的物件。官方給出的解釋也是說這個物件是非執行緒安全的。
但是mybatis對這個物件做了一個封裝SqlSessionTemplate物件。SqlSessionTemplate物件主要是對sqlsession做了一個執行緒安全的實現。就是用java的動態代理。
sqlsessionTemplate內部執有一個對sqlsession的一個代理物件。這個代理物件的實現就是生成一個新的sqlsession 這個sqlsession物件是從sqlsessionUtil.getsqlsession獲取到的。
這個類是在org.mybatis.spring包下面的是集成了spring的 。 它獲取sqlsession的時候會先從spring中去獲取。如果開啟了spring的事務管理。那麼你本次呼叫的sqlsession就會是你這次會話一個共用的sqlsession, 如果你沒有開啟事務的話,每次更新就會是一個新的sqlsession