手寫MyBatis第37彈: 深入MyBatis MapperProxy:揭秘SQL命令類型與動態方法調用的完美適配

🥂(?′?`?)您的點贊👍?評論📝?收藏?是作者創作的最大動力🤞

💖📕🎉🔥 支持我:點贊👍+收藏??+留言📝歡迎留言討論

🔥🔥🔥(源碼 + 調試運行 + 問題答疑)

🔥🔥🔥 ?有興趣可以聯系我。

我們常常在當下感到時間慢,覺得未來遙遠,但一旦回頭看,時間已經悄然流逝。對于未來,盡管如此,也應該保持一種從容的態度,相信未來仍有許多可能性等待著我們。?

目錄

一、MyBatis架構回顧與MapperProxy定位

二、SqlSession的多樣化設計:為什么需要多種查詢方法?

1. 返回結果類型的多樣性

2. 性能優化的考慮

3. API設計的清晰性

三、MapperProxy的動態適配機制

1. SQL命令類型識別

2. 返回類型分析與選擇策略

3. 參數處理與傳遞

四、高級特性與優化策略

1. 批量操作的特殊處理

2. 結果處理器集成

3. 緩存策略與延遲加載

五、實戰:自定義MapperProxy擴展

1. 性能監控增強

2. 自動重試機制

六、總結與最佳實踐


在現代Java開發中,MyBatis作為一款優秀的持久層框架,以其靈活的SQL映射和簡潔的API設計深受開發者喜愛。本文將深入剖析MyBatis核心組件之一的MapperProxy,探討它是如何根據SQL命令類型動態適配SqlSession的CRUD方法,實現Mapper接口方法與數據庫操作的無縫對接。

一、MyBatis架構回顧與MapperProxy定位

在深入了解MapperProxy之前,讓我們先簡要回顧MyBatis的核心架構。MyBatis通過SqlSession提供數據庫操作API,而Mapper接口則定義了這些操作的方法簽名。MapperProxy作為連接這兩者的橋梁,實現了Java動態代理模式,負責將接口方法調用轉化為具體的數據庫操作。

?public class MapperProxy<T> implements InvocationHandler {private final SqlSession sqlSession;private final Class<T> mapperInterface;@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 方法調用處理邏輯}}

二、SqlSession的多樣化設計:為什么需要多種查詢方法?

SqlSession提供了selectOneselectListselectMap等多種查詢方法,這種設計并非偶然,而是為了滿足不同場景下的數據檢索需求:

1. 返回結果類型的多樣性

  • selectOne:返回單個對象,適用于查詢唯一結果場景

  • selectList:返回對象列表,適用于多結果查詢

  • selectMap:返回鍵值對映射,便于基于特定字段快速查找

2. 性能優化的考慮

不同的方法內部實現針對特定場景進行了優化,比如selectOne在檢測到多個結果時會拋出異常,避免意外的數據覆蓋。

3. API設計的清晰性

明確的方法命名使得代碼更易讀和維護,開發者能夠直觀地理解每個方法的用途。

三、MapperProxy的動態適配機制

MapperProxy的核心職責是根據Mapper接口方法的特征,動態選擇適當的SqlSession方法。這一過程涉及多個關鍵判斷:

1. SQL命令類型識別

通過MappedStatement獲取sqlCommandType,這是決定調用哪個SqlSession方法的首要因素:

?public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName = method.getName();Class<?> declaringClass = method.getDeclaringClass();String statementId = declaringClass.getName() + "." + methodName;MappedStatement ms = configuration.getMappedStatement(statementId);SqlCommandType sqlCommandType = ms.getSqlCommandType();switch (sqlCommandType) {case SELECT:// 處理查詢操作break;case INSERT:return sqlSession.insert(statementId, args);case UPDATE:return sqlSession.update(statementId, args);case DELETE:return sqlSession.delete(statementId, args);default:throw new RuntimeException("Unknown execution method for: " + statementId);}}

2. 返回類型分析與選擇策略

對于SELECT操作,需要進一步分析方法的返回類型:

?private Object handleSelect(Method method, String statementId, Object[] args) {Class<?> returnType = method.getReturnType();if (List.class.isAssignableFrom(returnType)) {return sqlSession.selectList(statementId, args);} else if (Map.class.isAssignableFrom(returnType)) {// 處理Map返回類型,可能需要額外的key配置return sqlSession.selectMap(statementId, args, method.getAnnotation(MapKey.class).value());} else if (returnType.isArray()) {// 數組類型處理List<?> result = sqlSession.selectList(statementId, args);return convertToArray(result, returnType.getComponentType());} else {// 默認為selectOne,但需要驗證結果數量List<?> result = sqlSession.selectList(statementId, args);if (result.size() == 1) {return result.get(0);} else if (result.size() > 1) {throw new TooManyResultsException("Expected one result (or null) but found: " + result.size());} else {return null;}}}

3. 參數處理與傳遞

MapperProxy還需要正確處理方法的參數,支持多種參數傳遞方式:

private Object wrapParameters(Object[] args) {if (args == null || args.length == 0) {return null;} else if (args.length == 1) {return args[0];} else {// 多參數處理,可封裝為Map或使用@Param注解Map<String, Object> paramMap = new HashMap<>();for (int i = 0; i < args.length; i++) {paramMap.put("param" + (i + 1), args[i]);}return paramMap;}}

四、高級特性與優化策略

1. 批量操作的特殊處理

對于批量操作,MyBatis提供了特殊的API和優化策略:

?case BATCH:// 批量操作處理if (!sqlSession.isBatching()) {sqlSession.startBatch();}return method.invoke(this, args);

2. 結果處理器集成

支持自定義結果處理器,增強結果集處理的靈活性:

?if (method.isAnnotationPresent(ResultHandler.class)) {ResultHandler<?> handler = (ResultHandler<?>) args[args.length - 1];return sqlSession.select(statementId, wrapParameters(args), handler);}

3. 緩存策略與延遲加載

MapperProxy還需要與MyBatis的緩存機制和延遲加載功能協同工作:

?if (ms.getCache() != null && ms.isUseCache()) {// 緩存命中邏輯Object cached = cache.getObject(statementId);if (cached != null) {return cached;}}

五、實戰:自定義MapperProxy擴展

通過擴展MapperProxy,我們可以實現一些高級功能:

1. 性能監控增強

?public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long startTime = System.currentTimeMillis();try {return super.invoke(proxy, method, args);} finally {long cost = System.currentTimeMillis() - startTime;log.debug("Method {} executed in {} ms", method.getName(), cost);}}

2. 自動重試機制

for (int retry = 0; retry < maxRetries; retry++) {try {return super.invoke(proxy, method, args);} catch (SQLException e) {if (isRetryableException(e) && retry < maxRetries - 1) {continue;}throw e;}
}

六、總結與最佳實踐

MapperProxy作為MyBatis的核心組件,通過動態代理技術實現了Mapper接口方法與SqlSessionCRUD操作的無縫對接。其設計巧妙之處在于:

  1. 職責分離:將SQL命令類型判斷與具體執行分離,符合單一職責原則

  2. 靈活適配:根據返回類型自動選擇最合適的查詢方法

  3. 擴展性強:通過配置和擴展支持各種復雜場景

在實際開發中,理解MapperProxy的工作原理有助于:

  • 更好地調試Mapper接口相關問題

  • 根據業務需求選擇合適的返回類型

  • 優化數據庫操作性能

  • 實現自定義的數據訪問邏輯

通過深入理解MapperProxy的設計思想和實現機制,我們不僅能夠更好地使用MyBatis,還能夠在遇到復雜業務場景時做出更合理的技術決策。


進一步學習建議

  1. 閱讀MyBatis官方文檔中關于Mapper接口和SqlSession的部分

  2. 深入研究Java動態代理機制

  3. 探索MyBatis-Spring中MapperScannerConfigurer的工作原理

  4. 了解MyBatis的插件開發,實現自定義的攔截器功能

希望本文能夠幫助您深入理解MyBatis的核心機制,并在實際項目中更加得心應手地使用這一優秀的持久層框架。


💖學習知識需費心,
📕整理歸納更費神。
🎉源碼免費人人喜,
🔥碼農福利等你領!

💖常來我家多看看,
📕我是程序員扣棣,
🎉感謝支持常陪伴,
🔥點贊關注別忘記!

💖山高路遠坑又深,
📕大軍縱橫任馳奔,
🎉誰敢橫刀立馬行?
🔥唯有點贊+關注成!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/920271.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/920271.shtml
英文地址,請注明出處:http://en.pswp.cn/news/920271.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

GD32VW553-IOT 測評和vscode開發環境搭建

GD32VW553-IOT 測評和vscode開發環境搭建 1. 背景介紹 iCEasy商城的產品, Firefly Workshop 螢火工廠的樣片, 是一款基于GD32VW553 MCU的開源硬件, 這款MCU內置了32bit的RISC-V內核, 支持雙模無線WIFI-6和BLE-5.2, 最高主頻可達160Mhz. 本人曾在公司參與開發了一款基于RISC-V內…

斯塔克工業技術日志:用基礎模型打造 “戰甲級” 結構化 AI 功能

引子 在斯塔克工業的地下研發實驗室里&#xff0c;弧光反應堆的藍光映照著布滿代碼的顯示屏&#xff0c;工程師詹姆斯?“羅迪”?羅德斯正對著一堆 AI 生成的雜亂食譜皺眉。 上周他剛搞定基礎模型&#xff08;Foundation Models&#xff09;的文本生成&#xff0c;讓 AI 能像…

如何解決pip安裝報錯ModuleNotFoundError: No module named ‘click’問題

【Python系列Bug修復PyCharm控制臺pip install報錯】如何解決pip安裝報錯ModuleNotFoundError: No module named ‘click’問題 摘要 在日常Python開發中&#xff0c;pip install 報錯 ModuleNotFoundError: No module named click 是一個非常常見的問題&#xff0c;尤其是在…

PLC_博圖系列?基本指令”S_PULSE:分配脈沖定時器參數并啟動“

PLC_博圖系列?基本指令”S_PULSE&#xff1a;分配脈沖定時器參數并啟動“ 文章目錄PLC_博圖系列?基本指令”S_PULSE&#xff1a;分配脈沖定時器參數并啟動“背景介紹S_PULSE&#xff1a; 分配脈沖定時器參數并啟動說明參數脈沖時序圖示例關鍵字&#xff1a; PLC、 西門子、 …

【大模型】Qwen2.5-VL-3B模型量化以及運行測試,保留多模態能力(實踐版)

目錄 ■獲取原始模型 ■構建llama.cpp ■轉換模型到GGUF ▲視覺模塊轉換 ▲llm模塊轉換 ▲llm模塊量化 ▲推理測試 ■報錯處理 以下是幾種多模態模型量化方案的簡要對比: 特性 llama.cpp GGUF 量化

C語言 | 高級C語言面試題

側重于內存管理、指針、編譯器行為、底層原理和編程實踐。 C語言面試 一、核心概念與深度指針題 1. `const` 關鍵字的深度理解 2. volatile 關鍵字的作用 3. 復雜聲明解析 二、內存管理 4. `malloc(0)` 的行為 5. 結構體內存對齊與大小計算 三、高級技巧與底層原理 6. setjmp()…

【deepseek問答記錄】:chatGPT的參數數量和上下文長度有關系嗎?

這是一個非常好的問題&#xff0c;它觸及了大型語言模型設計的核心。 簡單來說&#xff1a;參數數量和上下文長度在技術上是兩個獨立的概念&#xff0c;但在模型的設計、訓練和實際應用中&#xff0c;它們存在著深刻且重要的聯系。 我們可以從以下幾個層面來理解它們的關系&…

5GNR CSI反饋 TypeI碼本

5GNR CSI反饋 TypeI碼本 前言 最近孬孬在學習5gnr中的CSI反饋內容&#xff0c;對于目前的5GNR主要是基于碼本的隱式反饋機制&#xff0c;在NR中主要是分為 TypeI 和 TypeII&#xff0c;對于TypeI是用于常規精度的&#xff0c;對于TypeII更為復雜&#xff0c;更多的適用于多用戶…

使用appium對安卓(使用夜神模擬器)運行自動化測試

環境安裝 基本環境安裝 安裝node.js 下載地址&#xff1a;Node.js — Run JavaScript Everywhere 安裝Java JDK 下載地址&#xff1a;JDK Builds from Oracle 安裝夜神模擬器 360上找下就能裝&#xff0c;安裝好后將夜神的bin目錄&#xff0c;添加到系統變量的path中。 …

用wp_trim_words函數實現WordPress截斷部分內容并保持英文單詞完整性

在WordPress中&#xff0c;wp_trim_words函數用于截斷字符串并限制單詞數量。如果你希望在截斷時保持單詞的完整性&#xff08;讓單詞顯示全&#xff09;&#xff0c;可以通過自定義函數來實現。 以下是一個示例代碼&#xff0c;展示如何修改你的代碼以確保截斷時顯示完整的單…

Codeforces Round 1042 (Div. 3) G Wafu! 題解

Codeforces Round 1042 (Div. 3) G Wafu! 題解 題意&#xff1a;每一次操作刪除集合中最小的元素 x&#xff0c;并產生新的 x - 1 個元素值分別為 1 2 3 … x - 1 放入集合之中。 每次操作一個數 x 可以使得最終答案乘上 x&#xff0c;問我們操作 k 次在模 1e9 7 的基礎上最終…

APP與WEB測試的區別?

web與app核心區別&#xff1a;一個基于瀏覽器 &#xff0c;一個基于操作系統這是所有區別的根源&#xff1a;Web測試&#xff1a;測試對象是網站&#xff0c;通過瀏覽器(Chrome,Firefox等)訪問&#xff0c;運行環境核心是瀏覽器引擎&#xff1b;App測試&#xff1a;測試對象是應…

2.滲透-.WEB運行原理-ZBlog安裝(進一步理解數據庫)

免責聲明&#xff1a;內容僅供學習參考&#xff0c;請合法利用知識&#xff0c;禁止進行違法犯罪活動&#xff01; 內容參考于&#xff1a;微塵網校 上一個內容&#xff1a;1.滲透-.WEB運行原理&#xff08;搭建一個WEB程序&#xff09; 首先把服務運行起來 然后訪問下圖紅框…

MapBox GL地圖上繪制圓形區域,在區域中心點添加標記點及文本提示的實現方法

MapBox GL地圖上繪制圓形區域&#xff0c;在區域中心點添加標記點及文本提示的實現方法&#xff1a;// 繪制影響區域 const addArea (circle) > {if (!map.current || !circle) return;const areaId circle-area;const epicenterId circle-epicenter;const radiusKm cir…

基于 Docker Compose 的若依多服務一鍵部署java項目實踐

基于Docker Compose的若依多服務一鍵部署實踐 在項目開發中&#xff0c;多服務部署常常讓人頭疼。環境配置復雜、操作步驟繁瑣&#xff0c;稍不注意就容易出錯。不過&#xff0c;有了 Docker Compose &#xff0c;這些問題就簡單多啦&#xff01;它能幫我們高效編排多個容器&am…

MyBatis-Plus 使用 Wrapper 自定義 SQL 查詢

目錄 1. 注意事項 2. 示例代碼 2.1 實體類 2.2 Mapper 接口 2.3 測試類 3. 運行效果 4. 總結 在實際項目中&#xff0c;雖然 MyBatis-Plus 提供了豐富的內置方法和 QueryWrapper 條件構造器&#xff0c;但有時我們需要 自定義 SQL 來實現更復雜的查詢邏輯。 MyBatis-Plu…

NumPy/PyTorch/C char數組內存排布

1. 關于 np.random.randn(2, 3) 的數據存儲數據類型 (Data Type)&#xff1a;np.random.randn 默認生成的是 64位&#xff08;8字節&#xff09;雙精度浮點數 (numpy.float64)。所以每個數字占 8個字節&#xff0c;而不是8位&#xff08;1字節&#xff09;。這是一個關鍵區別。…

Elasticsearch精準匹配與全文檢索對比

在 Elasticsearch 中&#xff0c;精準匹配檢索和全文檢索匹配檢索是兩種核心查詢方式&#xff0c;主要區別在于匹配規則、分詞處理、適用場景和底層實現邏輯。以下是詳細對比&#xff1a;一、核心區別總結特性精準匹配&#xff08;Term Query&#xff09;全文檢索&#xff08;M…

【鴻蒙開發001】上下翻頁-翻書效果實現【可復用】

先看效果&#xff1a;一、設計思路&#xff1a;根據所需要的最終效果&#xff0c;最終設計如下&#xff1a;&#xff08;1&#xff09;整體設計了4個模塊&#xff0c;這里分別標記為&#xff1a;A1&#xff0c;A2&#xff0c;B1&#xff0c;B2。具體說明如下&#xff1a;A模塊&…

H20 性能表現之 Qwen3-235B

上期為大家分享了H20性能表現之Qwen3-Coder-480B&#xff08;以下稱480B&#xff09;&#xff0c;今天&#xff0c;我為大家繼續帶來新的評測&#xff0c;這次&#xff0c;介紹的是 Qwen3-235B-A22B-Instruct-2507&#xff08;以下稱235B&#xff09;&#xff0c;這也是阿里這陣…