MyBatis 原理淺析——基本原理

前言

MyBatis 是一個被普遍應用的持久化框架。一個簡單的使用示例以下所示,先建立會話工廠,而後從會話工廠中打開會話,經過 class 類型和配置生成 Mapper 接口的代理實現,最後使用 Mapper 進行持久化操做。 java

本文將從 MyBatis 中的 SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession 和 Mapper 幾個方面入手簡單分析 MyBatis 的實現原理。在後面的系列文章中會進一步具體分析核心類的細節實現。程序員

 

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder 使用 Builder 模式去生成 SqlSessionFactory,所以只提供了多個 build 方法。這些方法能夠接受 XML 配置文件的 Reader 或 InputStream 輸入流,也能夠傳入 environment 指定環境或傳入 Properties 做爲屬性。sql

 在 build 方法的實現中,首先根據傳入的輸入流、environment 和 Properties 構建 XMLConfigBuilder 對象,而後調用其 parse() 方法解析 XML 文件獲得 Configuration 對象,最後建立 SqlSessionFactory 對象並返回。數據庫

 

SqlSessionFactory

SqlSessionFactory 是一個工廠接口,默認實現是 DefaultSqlSessionFactory。SqlSessionFactory 的做用是獲取 SqlSession,所以提供了多個 openSession 方法,支持從 DataSource 數據源和一個給定的鏈接 Connection 中建立 SqlSession。緩存

 openSession 方法的底層實現能夠分爲 5 步:微信

①從 Configuration 對象中獲取環境配置 Environment;session

②根據環境配置獲得事務工廠 TransactionFactory;app

③從事務工廠獲得事務 Transaction,Transaction 包裝了數據庫鏈接,處理數據庫鏈接的建立、準備、提交、回滾和關閉;框架

④建立執行器 Executor;分佈式

⑤建立 SqlSession,返回 DefaultSqlSession 的實例。

其中從 DataSource 數據源建立 SqlSession 的過程以下所示:

Java代碼   收藏代碼
  1. Transaction tx =null;  
  2. try{  
  3. finalEnvironment environment = configuration.getEnvironment();  
  4. finalTransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);  
  5. tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);  
  6. finalExecutor executor = configuration.newExecutor(tx, execType);  
  7. returnnewDefaultSqlSession(configuration, executor, autoCommit);  
  8. }catch(Exception e){  
  9. closeTransaction(tx);// may have fetched a connection so lets call close()  
  10. throwExceptionFactory.wrapException("Error opening session. Cause: "+ e, e);  
  11. }finally{  
  12. ErrorContext.instance().reset();  
  13. }  

 

 

SqlSession

SqlSession 是一個接口,默認實現是 DefaultSqlSession,提供了多種數據庫操做方式,如 select、selectOne、selectList、insert、update、delete、commit、rollback 和 getMapper 等方法。getMapper 方法用於獲取 Mapper 接口的代理實現。在 MyBatis 中建議使用 Mapper 接口操做數據庫。

 數據庫的增刪改查和事務的提交回滾都是經過 Executor 執行的。Executor 有 3 種類型 SIMPLE、REUSE、BATCH,默認使用簡易執行器 SIMPLE,REUSE 類型執行器重用預處理語句,BATCH 類型執行器重用預處理語句和批量更新。Executor 對象的建立在 Configuration 類型的 newExecutor 方法中進行。

 Executor 在執行過程當中,會用到 StatementHandler、ParameterHandler 和 ResultHandler,其中 StatementHandler 封裝了 java.sql.Statement 的相關操做,ParameterHandler 封裝了 SQL 對參數的處理,ResultHandler 封裝了對返回數據集的處理。Executor 的執行過程,就是對這 3 個對象的調度過程。更多分析在後續文章中進行。

 

Mapper

Mapper 是經過 JDK 動態代理實現的,在 MapperProxyFactory 中建立 MapperProxy 並進行接口代理封裝。對 Mapper 接口的調用其實是由 MapperProxy 實現的。

Java代碼   收藏代碼
  1. @SuppressWarnings("unchecked")  
  2. protected T newInstance(MapperProxy<T> mapperProxy){  
  3. return(T)Proxy.newProxyInstance(mapperInterface.getClassLoader(),newClass[]{ mapperInterface }, mapperProxy);  
  4. }  
  5.    
  6. public T newInstance(SqlSession sqlSession){  
  7. finalMapperProxy<T> mapperProxy =newMapperProxy<T>(sqlSession, mapperInterface, methodCache);  
  8. return newInstance(mapperProxy);  

在 MapperProxy 中,實現了 InvocationHandler 的 invoke 方法。methodCache 是一個 ConcurrentHashMap,其中存儲了方法與 MapperMethod 的對應關係。從 methodCache 緩存中獲取或建立 MapperMethod 對象,而後調用 MapperMethod 對象的 execute 方法執行數據庫操做。

Java代碼   收藏代碼
  1. @Override  
  2. publicObject invoke(Object proxy,Method method,Object[] args)throwsThrowable{  
  3. try{  
  4. if(Object.class.equals(method.getDeclaringClass())){  
  5. return method.invoke(this, args);  
  6. }elseif(isDefaultMethod(method)){  
  7. return invokeDefaultMethod(proxy, method, args);  
  8. }  
  9. }catch(Throwable t){  
  10. throwExceptionUtil.unwrapThrowable(t);  
  11. }  
  12. finalMapperMethod mapperMethod = cachedMapperMethod(method);  
  13. return mapperMethod.execute(sqlSession, args);  
  14. }  
  15.    
  16. privateMapperMethod cachedMapperMethod(Method method){  
  17. MapperMethod mapperMethod = methodCache.get(method);  
  18. if(mapperMethod ==null){  
  19. mapperMethod =newMapperMethod(mapperInterface, method, sqlSession.getConfiguration());  
  20. methodCache.put(method, mapperMethod);  
  21. }  
  22. return mapperMethod;  

建立 MapperMethod 對象時,會在構造函數中初始化 SqlCommand 和MethodSignature。SqlCommand 包含了數據庫操做的名稱,格式爲 「接口名.操做名稱」,以及 XML 中配置的操做類型,如 select、update等,把一個 Mapper 接口與 XML中的一個配置結合起來。MethodSignature 是方法的簽名,標記了方法的返回值類型,對於使用 RowBounds(offset 和 limit 配置)、ResultHandler(結果處理回調)做爲參數的方法記錄參數位置並初始化參數處理器。

在 MapperMethod 的 execute 方法中,根據 SqlCommand 中的配置選擇 SqlSession 的方法,根據 MethodSignature 的配置處理傳入的參數,調用 SqlSession 的方法進行數據庫操做,最後根據 MethodSignature 的返回值類型返回操做結果。

每週 3 篇學習筆記或技術總結,面向有必定基礎的 Java 程序員,內容涉及 Java 進階、虛擬機、MySQL、NoSQL、分佈式計算、開源框架等多個領域。關注做者或微信公衆號 backend-develop 第一時間獲取最新內容。

MyBatis 原理淺析--基本原理
相關文章
相關標籤/搜索