? ? 本文繼續(xù)沿用MyBatis系列 (1) ~ 啟動的demo,并在上文基礎上,說明MyBatis到底是如何執(zhí)行sql的。MyBatis執(zhí)行一個查詢方法,可以分為兩步:Session的創(chuàng)建和結(jié)果的獲取。本文的內(nèi)容是基于demo特定代碼的結(jié)果,如果你的配置文件或測試代碼不一致,結(jié)果可能不一樣。
一、Session的創(chuàng)建
? ? 1.如測試代碼所示【測試代碼和demo詳見MyBatis系列 (1) ~ 啟動】,調(diào)用ssf.openSession方法(圖1),將會返回一個session對象。而openSession()調(diào)用openSessionFromDataSource方法(圖2),在openSessionFromDataSource方法(圖3)中configuration.newExecutor會生成一個Executor實例(圖4),而這個Executor對象則是一個CachingExecutor實例,包裝了SimpleExecutor實例(圖5),最后再利用Executor創(chuàng)建DefaultSqlSession實例并返回(圖3),至此session創(chuàng)建完成。session對于sql的執(zhí)行,都是利用executor去完成,可以說Executor是seeeion最重要的對象。





二、結(jié)果的獲取
? ? 這個過程大概會經(jīng)過MappedStatement查找、BoundSql的創(chuàng)建、CacheKey的創(chuàng)建、緩存查找、JDBC操作(數(shù)據(jù)庫Connection建立、Statement建立、參數(shù)設置、結(jié)果處理)、緩存更新這幾個步奏。其中緩存的部分以后再分析。
? ? 1.MappedStatement查找。從Configuration對象的mappedStatements根據(jù)id獲取。mappedStatement如何添加到mappedStatements可以參照MyBatis系列 (1) ~ 啟動。

? ? ? ? 2.BoundSql的創(chuàng)建。調(diào)用MappedStatement的getBoundSql方法會創(chuàng)建并返回一個BoundSql實例。BoundSql會封裝好sql、參數(shù)、類型、typeHandler等信息,具體過程如下所示。

? ? ? ? ? 3.CacheKey的創(chuàng)建。調(diào)用CachingExecutor的createCacheKey方法會返回一個CacheKey對象實例。CacheKey根據(jù)MappedStatement的id,偏移量,sql,參數(shù),environment的id標識。如果他們都相等,則可以判斷CacheKey也相等。ddemo的CacheKey為"-1623403364:769426577:User.selectOneUser:0:2147483647:select t.id,t.name from user t where id = ?:2:development"。

? ? ? ? 4.JDBC操作。數(shù)據(jù)庫連接是在這里這里建立的,并不是一創(chuàng)建一個session實例就會建立一個連接。Connection由dataSource的doGetConnection方法返回。參數(shù)是由TypeHandler設置。





? ? ? ? 4.更新緩存。把相關(guān)結(jié)果存到localCache對象中,對于相同的CacheKey,如果緩存中有值,則不需要到數(shù)據(jù)庫去查詢。

? ? ? ? 最后把結(jié)果返回給調(diào)用者,至此,MyBatis查詢執(zhí)行結(jié)束。