1. 程式人生 > >MyBatis的解析和執行原理

MyBatis的解析和執行原理

MyBatis的執行可分為兩大部分,第一部分是讀取配置檔案快取到Configuration物件,用來建立SqlSessionFactory,第二部分是SqlSession的執行過程。

先匯入原始碼,不然你不知道方法之間是怎麼呼叫。

一構建SqlSessionFactory過程

第一步,通過org.apache.ibatis.builder.xml.XMLConfigBuilder來解析配置的XML檔案。我們一般是能過new SqlSessionFactoryBuilder().build()方法來建立SqlSessionFactory,最終於的是執行build(Reader reader, String environment, Properties properties)這個方法,接著建立一個XMLConfigBuilder物件來解析XML檔案,把讀到的資料存入到org.apache.ibatis.session.Configuration中 ,

在把資料 存入到Configuration是呼叫過org.apache.ibatis.builder.xml.XMLConfigBuilderr的parseConfiguration(XNode root)方法,原始碼如下:

是不是知道為什麼Mybatis的核心配置是有順序的,不能打破它的順序。

第二步,通過得到的configuration物件,呼叫qlSessionFactoryBuilder類中的build(Configuration config)方法,通過這個方法來呼叫DefaultSqlSessionFactory這類的構造方法

如果你想知道Mybatis所有的配置的資訊,除了看API之外,還可以能Configuration的原始碼。

二SqlSession執行過程

在舊版本的MyBatis或者是iBatis中,使用的更多是SqlSession介面的方法進行操作,但是有新版的MyBatis建議使用Mapper。

我們一般通過SqlSession的getMapper方法來得到Mapper,面這個方法最終是通過org.apache.ibatis.binding.MapperProxyFactory這個類的newInstance方法產生,這個的重要程式碼如下

我們可以看到動態代理對介面的繫結,它的作用就是生成動態代理物件。面代理的方法則被放到了MapperProxy類中。我們還要看MapperProxy的原始碼。

看到invoke方法,一旦mapper是一個代理物件,那麼它就會執行到invoke方法裡面,顯然mapper不是一個類,而是介面,所以它會生成MapperMethod物件,它是通過cachedMapperMethod方法對其初始化,然後執行execute方法,把sqlSession各當前執行的引數傳遞進去。我們檢視這個方法的原始碼:

我主要看result = executeForMany(sqlSession, args);這名個方法,再檢視這個方法的原始碼:

我們可以看到它最終還呼叫了SqlSession介面的方法,其它判斷成立的條件,還是呼叫SqlSession介面的方法。

現在我們可以知道為什麼MyBatis只用Mapper介面便能夠執行SQL,因為對映器的XML檔案的名稱空間對應的便是這個介面的全路徑,那麼它根據全路徑和方法但能夠繫結起來,通過動態代理技術,讓這個介面跑起來。

我們已經知道了對映器其實就是一個代理物件,進入MapperMethod的execute方法,通過簡單判斷就進入SqlSession介面提供的不同方法,但是不知道它們是怎麼樣執行的。Mapper執行的過程是通過Executor(代理執行器)、StatementHandler(使用JDBC的Statement和PrepareStatement進行操作)、ParameterHandler(用於SQL對引數的處理)、ResultHandler(對資料集ResultSet的封裝返回處理)。

執行器(Executor),它是真正執行JAVA與資料庫互動的東西,MyBatis提供了三種執行器,可心根據自己的需求在setting元素的defaultExecutorTope中配置,這裡不介紹,因為與這篇部落格關係不大,自己查API就可以了。我們開啟SimpleExecutor這個類,隨便開啟找一個方法,這裡為更好的體現方法的結構,這裡貼的方法如下:

我們可以看到它是根據 Configuration來構建StatementHandler,然後使用prepareStatement方法對SQl編譯 關對引數進行初始化,這個方法呼叫了StatementHandler的prepare()進行預編譯和基礎配置,然後通過StatementHandler的parameterize()來設定引數並執行。

資料庫會話器(StatementHandler)就是專門處理資料庫會話的,我們通過RoutingStatementHandler來得到StatementHandler物件,它也使用了代理設計模式,StatementHandler分為三種:CallableStatementHandler、SimpleStatementHandler和PreparedStatementHandler,在初始化的時候會根據上下文環境決定建立那個StatementHandler物件,我們以SimpleStatementHandler為例,我們 看下面的方法(在執行這個方法,還用呼叫instantiateStatement方法進行SQL預編譯)

由於執行前引數和SQl都被prepare()方法預編譯,引數在parameterixe()方法上已經進行了設定。

引數處理器(ParameterHandler)對預編譯語句進行引數設定。實現類(DefaultParameterHandler)

結果處理器(ResultSetHandler),實現類(DefaultResultSetHandler),預設情況是通過這個類來處理。

SqlSession執行總結:SqlSession是通過Executo建立StatementHandler來執行的,面StatementHandler要經過下面三步:prepared預編譯SQL;parameterize設定引數;query/執行SQl。