您現在的位置是:首頁 > 網路遊戲首頁網路遊戲

MyBatis基礎-配置檔案解析

簡介netfageweiketangarticledetails80767532在setting解析中,我們需要注意一個快取預設值的設定,即cacheEnabled,如下圖所示,它標誌著我們在執行sql時到底使用什麼執行器去完成我們的業

怎麼給主鍵新增自增

前言

MyBatis是常見的Java資料庫訪問層框架,

它的前身是 Apache 的開源專案 iBatis。MyBatis 消除了幾乎所有的 JDBC 程式碼和引數的手工設定以及對結果集的檢索封裝,是一個支援

普通 SQL 查詢,儲存過程和高階對映

的基於 Java 的優秀持久層框架。

在日常工作中,開發人員多數情況下是對底層的原理一知半解。因此帶著個人的興趣,希望從應用及原始碼的角度為讀者梳理MyBatis的底層機制。

目錄

本文按照以下順序展開。

Mybatis的配置檔案以及相關介紹

俯瞰整個流程設計

mybatis。xml

核心配置檔案解析

mappe配置檔案解析

全文總結。

Mybatis的配置檔案以及相關介紹

在MyBatis的整個生命週期中,包含兩類配置檔案,一類是配置基本資訊的

MyBatis.xml

(該名稱可以自定義),一類是定義具體sql的

xxxMapper.xml

檔案,接下來我們就深入瞭解這兩個檔案的設計理念和他絕妙的底層設計。

俯瞰整個流程設計

MyBatis基礎-配置檔案解析

從上圖可知,我們開發一個Mybatis應用的基本流程非常簡單,但是其中的配置檔案是怎樣一步步轉換為我們熟悉的java物件呢,他們之間又是如何相交甚歡呢?跟著我的腳步,讓我們一起深入腹地,剝開這層神秘的面紗。

mybatis.xml核心配置檔案解析

由上圖可知,我們將

mybatis.xml

檔案轉換為流後傳入了

SqlSessionFactoryBuilder

,使用構造者模式呼叫方法

build(...)

之後返回Session工廠,我們只講解有配置檔案的,因此方法後兩個引數為null,如下圖所示:

MyBatis基礎-配置檔案解析

XMLConfigBuilder

底層

使用的是

DOM

解析方式,並配合使用 XPath 解析 XML 配置檔案

XML 常見的解析方式有以下兩種: DOM、 SAX :

DOM 方式

DOM 基於樹形結構解析, 它會將整個文件讀入記憶體並構建一個 DOM 樹, 基於這棵樹的結構對各個節點進行解析。

優點:a。形成了樹結構,直觀好理解,程式碼更易編寫

b。解析過程中樹結構保留在記憶體中,方便修改

缺點:

a。當xml檔案較大時,對記憶體耗費比較大,容易影響解析效能並且造成記憶體溢位

SAX 方式

SAX 是基於事件模型的 XML 解析方式, 它不需要將整個 XML 文件載入到記憶體中, 而只需要將一部分 XML 文件的一部分載入到記憶體中, 即可開始解析。

優點:a。採用事件驅動模式,對記憶體耗費比較小

b。適用於只需要處理xml中資料時

缺點:a。不易編碼(需要藉助handler來進行解析)

b。很難同時訪問同一個xml中的多處不同資料(事件有先後順序的)

具體為什麼Mybatis使用DOM而不使用SAX,大家可以後續思考

接著呼叫parse()方法開始解析具體的xml節點資訊,如下圖所示:

MyBatis基礎-配置檔案解析

MyBatis基礎-配置檔案解析

settings可配置值參考:

https://blog。csdn。net/fageweiketang/article/details/80767532

在setting解析中,我們需要注意一個快取預設值的設定,即

cacheEnabled

,如下圖所示,它標誌著我們在執行sql時到底使用什麼執行器去完成我們的業務操作:

MyBatis基礎-配置檔案解析

plugins

是我們自定義的外掛,用於擴充套件我們的4大物件,四大物件分別為

Execute

StatementHandler

ParameterHandler

ResultSetHandler

,在執行流程解析我們會詳細講解

MyBatis基礎-配置檔案解析

下面我們主要講解一下

environments

mappers

,environments配置了我們底層使用的資料庫連線資訊。而mappers定義了我們執行的具體sql查詢。

environments執行流程如下,執行完成後將Environment物件新增到Config物件中:

MyBatis基礎-配置檔案解析

mappers節點裡面可以配置多種用於解析具體xml檔案的方式,我們只關注resource方式,透過該配置我們可以獲取到具體的xxxMapper,xml檔案,然後透過

XMLMapperBuilder

類的

parse()

進行後續的處理,如下圖所示:

MyBatis基礎-配置檔案解析

我們首先看一下bindMapperForNamespace方法,該方法主要是處理我們mapper標籤中的namespace值,如下所示

MyBatis基礎-配置檔案解析

addMapper(boundType)內部呼叫了mapperRegistry。addMapper方法用於建立代理工廠物件,

MapperRegistry

是Config內部非常重要的例項變數,它儲存了所有的介面對應的代理工廠物件,後續獲取Mapper物件都是透過該物件獲取:

MyBatis基礎-配置檔案解析

開始解析mapper標籤下面的所有資訊,如下圖所示

MyBatis基礎-配置檔案解析

其中

buildStatementFromContext()

就是我們的核心方法了,該方法底層呼叫了parseStatementNode()方法,parseStatementNode()將我們的CRUD中的各個子標籤以及配置的屬性進行轉換最終生成一個

MapperedStatemanet

物件並且儲存到Config物件中的mappedStatements變數裡。

public void parseStatementNode() { String id = context。getStringAttribute(“id”); String databaseId = context。getStringAttribute(“databaseId”); if (!databaseIdMatchesCurrent(id, databaseId, this。requiredDatabaseId)) { return; } String nodeName = context。getNode()。getNodeName(); SqlCommandType sqlCommandType = SqlCommandType。valueOf(nodeName。toUpperCase(Locale。ENGLISH)); boolean isSelect = sqlCommandType == SqlCommandType。SELECT; //是否重新整理快取 預設值:增刪改重新整理 查詢不重新整理 boolean flushCache = context。getBooleanAttribute(“flushCache”, !isSelect); //是否使用二級快取 預設值:查詢使用 增刪改不使用 boolean useCache = context。getBooleanAttribute(“useCache”, isSelect); boolean resultOrdered = context。getBooleanAttribute(“resultOrdered”, false); //替換Includes標籤為對應的sql標籤裡面的值 //具體配置使用可參考https://blog。csdn。net/qq_36761831/article/details/88698102 XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant); includeParser。applyIncludes(context。getNode()); //傳入引數 String parameterType = context。getStringAttribute(“parameterType”); Class<?> parameterTypeClass = resolveClass(parameterType); //解析配置的自定義指令碼語言驅動 mybatis plus //用於解析具體的sql語句 String lang = context。getStringAttribute(“lang”); LanguageDriver langDriver = getLanguageDriver(lang); //解析selectKey,該標籤使用與insert、update標籤內,透過一個查詢,把返回結果作為主鍵 //其中的order屬性設定需要注意,配置了自增的需要配置為AFTER,使用序列的配置為BEFORE //生成KeyGenerator物件新增到Config物件的keyGenerators變數中 processSelectKeyNodes(id, parameterTypeClass, langDriver); // Parse the SQL (pre: and were parsed and removed) //設定主鍵自增規則,只能在insert使用 KeyGenerator keyGenerator; String keyStatementId = id + SelectKeyGenerator。SELECT_KEY_SUFFIX; keyStatementId = builderAssistant。applyCurrentNamespace(keyStatementId, true); if (configuration。hasKeyGenerator(keyStatementId)) { keyGenerator = configuration。getKeyGenerator(keyStatementId); } else { keyGenerator = context。getBooleanAttribute(“useGeneratedKeys”, configuration。isUseGeneratedKeys() && SqlCommandType。INSERT。equals(sqlCommandType)) ? Jdbc3KeyGenerator。INSTANCE : NoKeyGenerator。INSTANCE; } //解析Sql 根據sql文字來判斷是否需要動態解析 如果沒有動態sql語句且 只有#{}的時候 直接靜態解析使用?佔位 當有 ${} 不解析 SqlSource sqlSource = langDriver。createSqlSource(configuration, context, parameterTypeClass); StatementType statementType = StatementType。valueOf(context。getStringAttribute(“statementType”, StatementType。PREPARED。toString())); Integer fetchSize = context。getIntAttribute(“fetchSize”); Integer timeout = context。getIntAttribute(“timeout”); String parameterMap = context。getStringAttribute(“parameterMap”); String resultType = context。getStringAttribute(“resultType”); Class<?> resultTypeClass = resolveClass(resultType); String resultMap = context。getStringAttribute(“resultMap”); String resultSetType = context。getStringAttribute(“resultSetType”); ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType); if (resultSetTypeEnum == null) { resultSetTypeEnum = configuration。getDefaultResultSetType(); } String keyProperty = context。getStringAttribute(“keyProperty”); String keyColumn = context。getStringAttribute(“keyColumn”); String resultSets = context。getStringAttribute(“resultSets”); builderAssistant。addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);}

下面我們分析其中最重要的SqlSource物件生成所對應的

LanguageDriver

介面的createSqlSource方法,LanguageDriver預設的實現類為

XMLLanguageDriver

。該方法判斷我們建立的sql是否是動態sql,動態sql包含${}識別符號,靜態sql只有#{}標識,當只有靜態sql時,在此處便將#{}替換為佔位符?,否則會在真正呼叫查詢介面的時候去替換。

MyBatis基礎-配置檔案解析

總結:

配置檔案的解析其實很簡單,它主要的作用就是將我們的配置轉換為我們對應的java實體類然後供後續執行時呼叫,下面我們一起來看一下整體的解析過程:

MyBatis基礎-配置檔案解析

透過上圖分析,我們發現它的整個解析流程非常優雅,每個重要模組的解析都是由單獨的物件進行處理的,每個類的分工非常明確,我們在研究原始碼的時候不僅要注意他的實現方式還有學習其中的設計,這也提升我們編碼水平的重要途徑。

如有不準確的地方,歡迎指正,謝謝

Top