1. 程式人生 > >深入理解mybatis

深入理解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. 1Statement每次執行sql語句,資料庫都要執行sql語句的編譯,最好用於僅執行一次查詢並返回結果的情形,效率高於PreparedStatement.
  2. 注:根據這個statement特性。如果一條sql語句使用了這個statement來進行資料操作。那麼mybatisSimpleStatementHandler是不會對引數進行處理的。它會預設認為你這條sql是沒有引數的。不會呼叫mybatisParamerHandler來進行引數處理
  3. 2PreparedStatement是預編譯的,使用PreparedStatement有幾個好處(mybatis預設是使用這個)
  4. a.在執行可變引數的一條SQL時,PreparedStatementStatement的效率高,因為DBMS預編譯一條SQL當然會比多次編譯一條SQL的效率要高。
  5. b.安全性好,有效防止Sql注入等問題。
  6. c.對於多次重複執行的語句,使用PreparedStament效率會更高一點,並且在這種情況下也比較適合使用batch
  7. d.程式碼的可讀性和可維護性。
  8. 3CallableStatement介面擴充套件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