MyBatis實戰(zhàn)避坑指南與高頻面試題解析
1. MyBatis面試翻車實錄那些年我們踩過的坑去年面某大廠時面試官突然扔出一連串MyBatis問題從基礎(chǔ)配置到源碼設(shè)計再到緩存機制和動態(tài)SQL問得我措手不及?;丶液笪艺砹诉@份血淚清單覆蓋了90%高頻考點和實際開發(fā)中的典型問題。如果你不想在面試時被吊打建議認真看完這些實戰(zhàn)經(jīng)驗。重要提示本文所有案例均基于MyBatis 3.5.10 Spring Boot 2.7環(huán)境驗證不同版本可能存在差異1.1 為什么一級緩存會導(dǎo)致事務(wù)內(nèi)查詢不到最新數(shù)據(jù)上周我們線上就出現(xiàn)過這個問題在Transactional方法內(nèi)先更新數(shù)據(jù)再查詢結(jié)果返回的卻是舊數(shù)據(jù)。根本原因在于MyBatis的一級緩存SqlSession級別默認開啟且不受事務(wù)隔離級別控制。解決方案有三種在mapper方法上添加Options(flushCachetrue)直接調(diào)用sqlSession.clearCache()最徹底的方案是配置localCacheScopeSTATEMENT// 典型錯誤示例 Transactional public void updateAndQuery(Long id) { userMapper.updateStatus(id, 0); // 更新狀態(tài) User user userMapper.selectById(id); // 這里拿到的可能是緩存舊數(shù)據(jù) }1.2 動態(tài)SQL避坑指南1.2.1 XML中特殊符號轉(zhuǎn)義最近在金融項目里處理金額比較時就踩過這個坑!-- 錯誤寫法 -- if testamount 1000.../if !-- 正確寫法 -- if testamount lt; 1000.../if建議安裝MyBatisX插件它會自動提示XML中的語法問題。其他需要轉(zhuǎn)義的符號包括 () () () () ()1.2.2 動態(tài)傳參最佳實踐當需要傳入List 時新手常犯的錯誤!-- 錯誤示范 -- select idgetByIds resultTypeUser SELECT * FROM user WHERE id IN foreach collectionlist itemid open( separator, close) #{id} /foreach /select問題在于參數(shù)名應(yīng)該與Param注解一致ListUser getByIds(Param(idList) ListLong ids);!-- 正確寫法 -- foreach collectionidList itemid ...1.3 MyBatis Plus實戰(zhàn)技巧1.3.1 主鍵自增重置方案在測試環(huán)境經(jīng)常需要重置自增ID可以通過以下SQL實現(xiàn)ALTER TABLE your_table AUTO_INCREMENT1;如果使用MyBatis Plus的IdType.AUTO需要注意實體類標注TableId(type IdType.AUTO)數(shù)據(jù)庫字段必須設(shè)置AUTO_INCREMENT執(zhí)行truncate table會比delete更徹底1.3.2 從MyBatis遷移到MyBatis Plus我們項目從3.5.3升級到3.7時的主要改動點移除所有手動編寫的CRUD XML修改Mapper接口繼承BaseMapper調(diào)整分頁插件配置新版使用MybatisPlusInterceptor注意Version樂觀鎖注解的變化// 舊版配置 Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } // 新版配置 Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; }2. 源碼級深度解析2.1 執(zhí)行流程核心鏈路通過打斷點跟蹤我梳理出最關(guān)鍵的七個步驟SqlSessionFactoryBuilder解析XML構(gòu)建ConfigurationMapperProxy動態(tài)代理生成Mapper實例MappedStatement緩存SQL指令模板Executor處理緩存和事務(wù)StatementHandler構(gòu)建PreparedStatementParameterHandler處理參數(shù)映射ResultSetHandler轉(zhuǎn)換結(jié)果集其中最容易出問題的環(huán)節(jié)是參數(shù)處理特別是當使用Map傳參時MapString, Object params new HashMap(); params.put(name, 張三); params.put(age, 25); userMapper.selectByMap(params); // 這里Map的key必須與XML中的#{key}嚴格匹配2.2 插件開發(fā)實戰(zhàn)去年我們項目需要做數(shù)據(jù)權(quán)限控制通過自定義插件實現(xiàn)Intercepts({ Signature(type Executor.class, methodquery, args{MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) }) public class DataPermissionInterceptor implements Interceptor { Override public Object intercept(Invocation invocation) throws Throwable { // 1. 獲取原始SQL BoundSql boundSql ((MappedStatement)invocation.getArgs()[0]) .getBoundSql(invocation.getArgs()[1]); // 2. 拼接權(quán)限條件 String newSql boundSql.getSql() AND dept_id getCurrentDeptId(); // 3. 重置SQL resetSql(invocation, newSql); return invocation.proceed(); } }關(guān)鍵點通過Intercepts聲明攔截目標使用MetaObject修改final字段注意線程安全問題3. 性能優(yōu)化方案3.1 二級緩存正確打開方式我們電商項目曾因不當使用二級緩存導(dǎo)致庫存超賣!-- 危險配置 -- cache evictionLRU size1024/改進方案對實時性要求高的數(shù)據(jù)如庫存關(guān)閉二級緩存配置blockingtrue避免緩存擊穿實現(xiàn)Cache接口接入Rediscache typecom.company.MyRedisCache property nameexpireTime value3600/ /cache3.2 批量操作性能對比測試10萬條數(shù)據(jù)插入方式耗時(ms)內(nèi)存消耗(MB)單條循環(huán)插入285001200BatchExecutor3200350拼接VALUES批量插入800150推薦寫法// 方式1使用BatchExecutor Options(useGeneratedKeys true, keyProperty id) Insert(scriptINSERT INTO user(name,age) VALUES foreach collectionlist itemitem separator, (#{item.name},#{item.age})/foreach/script) void batchInsert(Param(list) ListUser users); // 方式2復(fù)用PreparedStatement SqlSession session sqlSessionFactory.openSession(ExecutorType.BATCH); try { UserMapper mapper session.getMapper(UserMapper.class); for (User user : userList) { mapper.insert(user); } session.commit(); } finally { session.close(); }4. 經(jīng)典面試題剖析4.1 #{}和${}的區(qū)別這道題十個候選人九個答不全特性#{}${}預(yù)處理是PreparedStatement否直接拼接SQL安全防護防SQL注入有注入風(fēng)險類型轉(zhuǎn)換自動需要手動處理適用場景參數(shù)值動態(tài)表名/列名實際項目中我們嚴格限制${}的使用必須經(jīng)過安全校驗// 安全使用動態(tài)表名示例 public ListUser queryByTable(String tableName) { if(!tableName.matches([a-zA-Z_0-9])) { throw new IllegalArgumentException(Invalid table name); } return userMapper.queryFromTable(tableName); }4.2 與Hibernate的核心差異去年做技術(shù)選型時我們做的對比維度MyBatisHibernateORM程度半自動需寫SQL全自動性能更優(yōu)直接控制SQL需要優(yōu)化緩存學(xué)習(xí)曲線平緩陡峭適用場景復(fù)雜查詢/性能敏感快速開發(fā)/簡單CRUD動態(tài)SQLXML/注解靈活Criteria API較復(fù)雜特別在報表類系統(tǒng)中我們堅持使用MyBatis復(fù)雜SQL可調(diào)優(yōu)避免N1查詢問題精準控制結(jié)果集5. 開發(fā)工具鏈推薦5.1 IDEA高效插件MyBatisX必備XML與接口方法跳轉(zhuǎn)SQL語法檢查代碼生成MyBatis Log Plugin控制臺SQL轉(zhuǎn)可執(zhí)行語句參數(shù)自動填充耗時統(tǒng)計Arthas線上診斷watch org.apache.ibatis.binding.MapperProxy invoke跟蹤Mapper方法調(diào)用5.2 代碼生成技巧我們團隊定制的生成模板!-- generatorConfig.xml片段 -- table tableNameuser domainObjectNameUser property nameuseActualColumnNames valuefalse/ generatedKey columnid sqlStatementSELECT LAST_INSERT_ID()/ columnOverride columncreate_time propertycreateTime javaTypejava.time.LocalDateTime/ /table關(guān)鍵優(yōu)化點使用Java8日期類型統(tǒng)一命名風(fēng)格駝峰式自動生成ResultMap生成Swagger注解6. 復(fù)雜場景解決方案6.1 多數(shù)據(jù)源事務(wù)管理在微服務(wù)拆分過渡期我們這樣處理跨庫事務(wù)Configuration MapperScan(basePackages com.dao.db1, sqlSessionTemplateRef db1SqlSessionTemplate) public class Db1Config { Bean ConfigurationProperties(prefix spring.datasource.db1) public DataSource db1DataSource() { return DataSourceBuilder.create().build(); } Bean public PlatformTransactionManager db1TxManager(Qualifier(db1DataSource) DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } } // 使用示例 Transactional(transactionManager db1TxManager) public void crossDbOperation() { db1Mapper.insert(...); db2Mapper.update(...); // 這里會拋出異常 }6.2 分庫分表實踐訂單表按月分表方案public class OrderShardingStrategy implements TableShardingStrategy { Override public String determineTableName(String logicTable, Object params) { OrderQuery query (OrderQuery)params; return order_ query.getCreateTime().format(DateTimeFormatter.ofPattern(yyyyMM)); } } // 配置 ShardingTableConfig config new ShardingTableConfig(); config.setLogicTable(order); config.setActualDataNodes(db.order_${202301..202312}); config.setTableShardingStrategy(new OrderShardingStrategy());7. 升級遷移注意事項從3.5升級到3.7的兼容性問題日志實現(xiàn)變化移除對log4j1.x的直接支持新增JdbcType.TIME_WITH_TIMEZONE處理Param注解變?yōu)楸仨毊攨?shù)名與占位符不一致時動態(tài)SQL的AND/OR前綴處理更嚴格建議升級步驟先升級到3.5.13過渡版本運行測試用例檢查日志輸出重點檢查動態(tài)SQL片段驗證分頁插件行為!-- 依賴管理示例 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.7.0/version /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version3.0.3/version /dependency8. 生產(chǎn)環(huán)境血淚教訓(xùn)8.1 連接泄露排查某次大促前壓測發(fā)現(xiàn)的典型問題// 錯誤示例 public ListUser queryUsers() { SqlSession session sqlSessionFactory.openSession(); return session.selectList(queryUsers); // 忘記關(guān)閉session! }排查工具Druid的removeAbandoned配置使用jstack查看線程棧添加連接生命周期監(jiān)控8.2 超大結(jié)果集處理導(dǎo)出百萬數(shù)據(jù)時的優(yōu)化方案// 流式查詢示例 Select(SELECT * FROM large_table) Options(resultSetType ResultSetType.FORWARD_ONLY, fetchSize Integer.MIN_VALUE) void streamQuery(ResultHandlerUser handler); // 使用方式 userMapper.streamQuery(resultContext - { User user resultContext.getResultObject(); // 逐行處理 if(resultContext.getResultCount() % 10000 0) { System.out.println(已處理 resultContext.getResultCount()); } });關(guān)鍵參數(shù)fetchSizeInteger.MIN_VALUE 啟用流式ResultSetType.FORWARD_ONLY 只進游標配合ResultHandler逐行消費9. 架構(gòu)設(shè)計思想9.1 插件體系設(shè)計MyBatis插件本質(zhì)是基于責(zé)任鏈模式// 簡化后的調(diào)用鏈 public class Plugin implements InvocationHandler { private Object target; private Interceptor interceptor; public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(!interceptor.getClass().isAnnotationPresent(Intercepts.class)) { return method.invoke(target, args); } return interceptor.intercept(new Invocation(target, method, args)); } }開發(fā)插件時的黃金法則不要修改原始參數(shù)謹慎處理ResultSet避免遞歸調(diào)用9.2 緩存設(shè)計哲學(xué)一級緩存設(shè)計精妙之處與SqlSession生命周期綁定執(zhí)行update操作自動清除可配置為STATEMENT級別二級緩存注意事項事務(wù)提交后才生效需要序列化實體類避免多表關(guān)聯(lián)查詢!-- 安全的緩存配置示例 -- cache typeorg.mybatis.caches.ehcache.EhcacheCache property nametimeToIdleSeconds value1800/ property namememoryStoreEvictionPolicy valueLRU/ /cache10. 前沿生態(tài)整合10.1 與Spring Boot深度集成自動配置的核心邏輯通過AutoConfigureAfter確定初始化順序根據(jù)spring.datasource.*創(chuàng)建DataSource掃描Mapper接口注冊MapperFactoryBean配置MyBatisProperties中的各項參數(shù)自定義集成方案Configuration public class MyBatisCustomConfig { Bean public ConfigurationCustomizer configurationCustomizer() { return configuration - { configuration.setMapUnderscoreToCamelCase(true); configuration.setDefaultFetchSize(100); configuration.setLazyLoadingEnabled(true); }; } }10.2 云原生適配在K8s環(huán)境中的最佳實踐使用HikariCP替代Druid更輕量配置健康檢查端點management: endpoints: web: exposure: include: health,info health: db: enabled: true動態(tài)數(shù)據(jù)源切換方案Around(annotation(ds)) public Object switchDataSource(ProceedingJoinPoint pjp, DS ds) throws Throwable { String dsKey DynamicDataSourceHolder.getDataSourceKey(); try { DynamicDataSourceHolder.setDataSourceKey(ds.value()); return pjp.proceed(); } finally { DynamicDataSourceHolder.setDataSourceKey(dsKey); } }

相關(guān)新聞

提示詞工程失效?AI風(fēng)格渲染不一致的12個隱藏參數(shù),90%工程師從未調(diào)優(yōu)過

提示詞工程失效?AI風(fēng)格渲染不一致的12個隱藏參數(shù),90%工程師從未調(diào)優(yōu)過

更多請點擊: https://kaifayun.com 第一章:提示詞工程失效的底層歸因診斷 提示詞工程并非萬能解藥,其表面失效往往映射著更深層的系統(tǒng)性斷層。當精心設(shè)計的指令無法穩(wěn)定觸發(fā)預(yù)期行為時,問題極少源于措辭本身,而多根植…

2026/8/3 9:58:41 閱讀更多
SSM框架在高校團委管理系統(tǒng)中的實踐與優(yōu)化

SSM框架在高校團委管理系統(tǒng)中的實踐與優(yōu)化

1. 項目概述:高校團委管理系統(tǒng)的核心價值高校團委作為學(xué)生工作的核心樞紐,每天需要處理大量事務(wù)性工作:團員信息管理、活動審批、志愿服務(wù)統(tǒng)計、評優(yōu)評先等。傳統(tǒng)Excel紙質(zhì)檔案的管理方式已經(jīng)難以應(yīng)對日益增長的數(shù)據(jù)量和協(xié)作需求。我去年為某…

2026/8/3 9:58:41 閱讀更多
游戲數(shù)據(jù)分析項目部署指南:從環(huán)境配置到功能驗證

游戲數(shù)據(jù)分析項目部署指南:從環(huán)境配置到功能驗證

這次我們來看一個名為“無能的馬克 半途而廢的輔助 大起大落的阿軻”的項目。從標題來看,這很可能是一個與游戲角色或游戲數(shù)據(jù)分析相關(guān)的工具,或許涉及對《王者榮耀》中“馬克”(馬可波羅)、“阿軻”等英雄的玩法、勝率、出裝或?qū)Α?/p>

2026/8/3 10:58:45 閱讀更多
ATK磁軸鍵盤驅(qū)動安裝與性能調(diào)優(yōu)全攻略:從快速觸發(fā)到RGB燈效

ATK磁軸鍵盤驅(qū)動安裝與性能調(diào)優(yōu)全攻略:從快速觸發(fā)到RGB燈效

1. 背景與核心概念 在機械鍵盤領(lǐng)域,磁軸鍵盤憑借其獨特的觸發(fā)原理和可調(diào)節(jié)性,正成為追求極致性能和個性化體驗玩家的新寵。然而,許多用戶在初次接觸這類設(shè)備時,往往會卡在驅(qū)動安裝與配置這一關(guān)。網(wǎng)上資料要么過于零散,…

2026/8/3 10:58:45 閱讀更多
3分鐘搞定!QQ空間歷史說說完整備份終極指南

3分鐘搞定!QQ空間歷史說說完整備份終極指南

3分鐘搞定!QQ空間歷史說說完整備份終極指南 【免費下載鏈接】GetQzonehistory 獲取QQ空間發(fā)布的歷史說說 項目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾想過,那些年發(fā)過的QQ空間說說,那些記錄青春的文字…

2026/8/2 0:04:01 閱讀更多
AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O分配PCB板是應(yīng)用材料(Applied Materials)公司生產(chǎn)的一款用于半導(dǎo)體設(shè)備的I/O信號分配電路板。該型號(0100-02186)的核心特點如下:專用于Endura等半導(dǎo)體工藝腔室。集成信號路由與分配功能。連接控制…

2026/8/2 2:51:21 閱讀更多
Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動機

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動機

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動機是日本日清(Nissei)品牌的一款工業(yè)用三相異步電機,適用于自動化設(shè)備及通用機械驅(qū)動。該型號(FFMN-32L-10-T0 40AX)的核心特點如下:三相交流異步電動機。額定…

2026/8/2 2:52:49 閱讀更多