????????在前兩篇博客中,我們掌握了 MyBatis 的基礎搭建、核心架構與 Mapper 代理開發,能應對簡單的單表 CRUD 場景。但實際項目中,業務往往更復雜 —— 比如 “多條件動態查詢”“員工與部門的關聯查詢”“高頻查詢的性能優化” 等。本篇將聚焦 MyBatis 的三大高級特性:動態 SQL(靈活拼接 SQL)、關聯查詢(處理多表關系)、查詢緩存(提升性能),結合文檔中的實戰案例,幫你解決復雜業務場景,真正做到 “學以致用”。
目錄
一、動態 SQL:MyBatis 的 “靈活拼接神器”
1.1 動態 SQL 的核心價值
1.2 核心動態 SQL 標簽實戰
(1)標簽:基礎條件判斷
(2)標簽:智能處理 AND/OR
(3)--標簽:二選一的條件
(4)標簽:自定義前綴 / 后綴
(5)標簽:動態更新的 “逗號殺手”
(6)標簽:處理集合與 IN 條件
(7)片段:SQL 代碼復用
(8)標簽:跨數據庫模糊查詢
二、關聯查詢:處理多表關系(一對一 / 一對多 / 多表)
2.1 關聯查詢的核心概念
2.2 一對一關聯查詢:員工→部門
實現步驟:
2.3 一對多關聯查詢:部門→員工
實現步驟:
2.4 多表關聯查詢:用戶→訂單→訂單詳情→商品
實現步驟:
三、查詢緩存:MyBatis 的 “性能優化利器”
3.1 緩存的核心概念
3.2 一級緩存:SqlSession 級別的本地緩存
核心特點:
實戰案例:
3.3 二級緩存:Mapper 級別的全局緩存
核心特點:
配置步驟:
實戰案例:
關鍵配置:
3.4 整合第三方緩存:Ehcache(分布式場景)
配置步驟:
四、總結:MyBatis 核心能力回顧與實踐建議
實踐建議:
一、動態 SQL:MyBatis 的 “靈活拼接神器”
????????實際開發中,SQL 語句往往不是固定的 —— 比如 “查詢員工” 時,用戶可能輸入姓名查詢,也可能輸入部門號查詢,還可能兩者都輸入。如果為每種情況寫一個 SQL,會導致代碼冗余。MyBatis 的動態 SQL 通過標簽判斷條件,自動拼接 SQL,徹底解決這一問題。
1.1 動態 SQL 的核心價值
動態 SQL 的本質是 “根據參數是否為空或滿足條件,動態生成合法的 SQL 語句”,避免手動拼接 SQL 的痛點:
- 無需擔心 “第一個條件是 AND/OR” 導致的語法錯誤;
- 無需處理 “字段末尾多余逗號”(如更新操作中);
- 支持循環遍歷集合(如
IN
條件),簡化批量操作。
MyBatis 提供 8 種常用動態 SQL 標簽,我們結合文檔中的實戰案例,逐一講解核心用法。
1.2 核心動態 SQL 標簽實戰
(1)<if>
標簽:基礎條件判斷
<if>
標簽是動態 SQL 的基礎,用于 “滿足條件則拼接 SQL 片段”,常與test
屬性(OGNL 表達式)配合使用。
場景:查詢員工,姓名不為空則按姓名模糊查詢,部門號不為空則按部門號查詢。
<select id="selectEmpByCond" parameterType="emp" resultType="emp">select * from emp where 1=1<!-- 若ename不為空且非空字符串,拼接姓名條件 --><if test="ename != null and ename != ''">and ename like concat('%', #{ename}, '%')</if><!-- 若deptno不為空,拼接部門號條件 --><if test="deptno != null">and deptno = #{deptno}</if>
</select>
關鍵說明:
test="ename != null and ename != ''"
:判斷參數ename
是否有效(非空且非空字符串);concat('%', #{ename}, '%')
:MySQL 中拼接模糊查詢的%
,避免 SQL 注入(文檔中強調#{}
比${}
更安全);where 1=1
:臨時占位,避免 “第一個條件是 AND” 導致的語法錯誤(后續<where>
標簽可替代這一寫法)。
(2)<where>
標簽:智能處理 AND/OR
<where>
標簽是<if>
標簽的 “好搭檔”,能自動處理條件拼接中的語法問題:
- 若內部有滿足條件的
<if>
,自動添加WHERE
關鍵字; - 自動去掉第一個條件前的
AND
或OR
; - 若內部無滿足條件的
<if>
,不添加WHERE
,避免語法錯誤。
優化上述<if>
案例:
<select id="selectEmpByCond" parameterType="emp" resultType="emp">select * from emp<where><if test="ename != null and ename != ''">and ename like concat('%', #{ename}, '%') <!-- 無需擔心第一個條件是AND --></if><if test="deptno != null">and deptno = #{deptno}</if></where>
</select>
文檔要點:<where>
標簽會智能忽略條件開頭的AND/OR
,且無需手動寫where 1=1
,代碼更簡潔。
(3)<choose>-<when>-<otherwise>
標簽:二選一的條件
類似 Java 的switch-case-default
,<choose>
標簽下的<when>
按順序判斷,只執行第一個滿足條件的<when>
,都不滿足則執行<otherwise>
。
場景:查詢員工,優先按薪資查(薪資≤指定值),其次按姓名查,都不滿足則查部門號 = 10。
<select id="selectEmpByChoose" parameterType="emp" resultType="emp">select * from emp<where><choose><when test="sal != null">sal <= #{sal} <!-- XML中“<”需轉義為“<” --></when><when test="ename != null and ename != ''">ename like concat('%', #{ename}, '%')</when><otherwise>deptno = 10 <!-- 所有條件不滿足時執行 --></otherwise></choose></where>
</select>
文檔說明:<choose>
適用于 “多個條件中只選一個” 的場景,避免<if>
標簽的 “多條件同時生效” 問題。
(4)<trim>
標簽:自定義前綴 / 后綴
<trim>
標簽比<where>
更靈活,支持自定義 “添加前綴”“添加后綴”“覆蓋首尾字符”,核心屬性如下:
prefix
:給內部內容添加前綴(如WHERE
);suffix
:給內部內容添加后綴(如)
);prefixOverrides
:去掉內部內容開頭的指定字符(如AND/OR
);suffixOverrides
:去掉內部內容末尾的指定字符(如,
)。
場景 1:替代<where>
標簽
<trim prefix="where" prefixOverrides="and|or"><if test="ename != null">and ename like '%${ename}%'</if><if test="deptno != null">and deptno = #{deptno}</if>
</trim>
場景 2:動態插入字段(處理末尾逗號)
插入操作中,若部分字段為空,會導致INSERT
語句末尾多逗號,<trim>
可自動去掉:
<insert id="insertEmp" parameterType="emp">insert into emp<!-- 動態拼接字段名,去掉末尾逗號 --><trim prefix="(" suffix=")" suffixOverrides=","><if test="ename != null">ename,</if><if test="job != null">job,</if><if test="sal != null">sal,</if></trim>values<!-- 動態拼接字段值,去掉末尾逗號 --><trim prefix="(" suffix=")" suffixOverrides=","><if test="ename != null">#{ename},</if><if test="job != null">#{job},</if><if test="sal != null">#{sal},</if></trim>
</insert>
文檔要點:<trim>
標簽是動態 SQL 中最靈活的標簽,可應對<where>
和<set>
無法覆蓋的場景。
(5)<set>
標簽:動態更新的 “逗號殺手”
更新操作中,若用<if>
標簽,可能出現 “字段末尾多逗號”(如update emp set ename=?,
),<set>
標簽可自動去掉末尾逗號,并添加SET
關鍵字。
場景:動態更新員工信息,字段不為空則更新該字段。
<update id="updateEmp" parameterType="emp">update emp<set><if test="ename != null">ename = #{ename},</if><if test="job != null">job = #{job},</if><if test="sal != null">sal = #{sal},</if></set>where empno = #{empno}
</update>
文檔說明:<set>
標簽會自動添加SET
關鍵字,并去掉內部內容末尾的逗號,避免update
語句語法錯誤。
(6)<foreach>
標簽:處理集合與 IN 條件
????????當 SQL 需要IN
條件(如where deptno in (10,20,30)
)或批量操作時,<foreach>
標簽可遍歷集合生成對應 SQL 片段,核心屬性如下:
collection
:集合類型(list
=List,array
= 數組,map的key
=Map 中的集合);open
:遍歷開始符號(如(
);close
:遍歷結束符號(如)
);item
:集合元素的別名(如deptno
);separator
:元素之間的分隔符(如,
)。
場景 1:遍歷 List 集合,查詢部門號在列表中的員工
<select id="selectEmpByDeptnos" parameterType="java.util.List" resultType="emp">select * from emp<where>deptno in<foreach collection="list" open="(" close=")" item="deptno" separator=",">#{deptno}</foreach></where>
</select>
場景 2:遍歷數組,查詢員工編號在數組中的員工
<select id="selectEmpByEmpnosArr" parameterType="int[]" resultType="emp">select * from emp<where>empno in<foreach collection="array" open="(" close=")" item="empno" separator=",">#{empno}</foreach></where>
</select>
文檔要點:collection
屬性需根據參數類型選擇(List 用list
,數組用array
),若參數是 Map,需寫 Map 中集合的key
。
(7)<sql>
片段:SQL 代碼復用
????????若多個 SQL 有重復片段(如select empno, ename, job from emp
),可提取為<sql>
片段,避免重復書寫,提升維護性。
<!-- 定義SQL片段:id為片段唯一標識 -->
<sql id="empColumns">empno, ename, job, sal, deptno
</sql><!-- 引用SQL片段:用<include refid="片段id"> -->
<select id="selectEmp" resultType="emp">select <include refid="empColumns"/> from emp
</select><select id="selectEmpByDeptno" parameterType="int" resultType="emp">select <include refid="empColumns"/> from emp where deptno = #{deptno}
</select>
文檔說明:<sql>
片段適用于重復的字段列表、查詢條件等,減少代碼冗余。
(8)<bind>
標簽:跨數據庫模糊查詢
????????不同數據庫的模糊查詢語法不同(MySQL 用concat
,Oracle 用||
),<bind>
標簽可定義變量統一語法,提升代碼可移植性。
<select id="selectEmpByEname" parameterType="emp" resultType="emp"><!-- 定義變量name:值為“%+ename+%” --><bind name="name" value="'%' + ename + '%'"/>select * from emp where ename like #{name}
</select>
文檔要點:<bind>
標簽無需關心數據庫類型,統一用#{name}
引用變量,避免因數據庫切換修改 SQL。
二、關聯查詢:處理多表關系(一對一 / 一對多 / 多表)
????????實際業務中,單表查詢很少見,更多是 “員工 - 部門”“部門 - 員工”“用戶 - 訂單 - 商品” 等多表關聯場景。MyBatis 通過<resultMap>
標簽的<association>
(一對一)和<collection>
(一對多)子標簽,實現復雜關聯映射。
2.1 關聯查詢的核心概念
在講解案例前,需明確兩種常見關聯關系:
- 一對一:一個對象對應一個對象(如一個員工對應一個部門);
- 一對多:一個對象對應多個對象(如一個部門對應多個員工);
- 多對多:需通過中間表轉換為 “一對多 + 多對一”(如用戶 - 訂單 - 商品,用戶與商品是多對多,通過訂單表關聯)。
MyBatis 通過<resultMap>
定義關聯規則,無需手動遍歷多表結果集,自動映射為實體類對象。
2.2 一對一關聯查詢:員工→部門
場景:查詢員工信息時,同時查詢員工所屬的部門信息(一個員工只屬于一個部門)。
實現步驟:
定義實體類:在Emp
類中添加Dept
屬性,存儲關聯的部門信息。
public class Emp {private int empno;private String ename;private int deptno;private Dept dept; // 一對一關聯:員工所屬部門// getter/setter、toString()
}public class Dept {private int deptno;private String dname;private String loc;// getter/setter、toString()
}
編寫 Mapper 接口:定義查詢方法。
public interface EmpMapper {List<Emp> selectEmpWithDept(); // 查詢員工及所屬部門
}
配置 Mapper.xml:用<resultMap>
+<association>
定義關聯映射。
<mapper namespace="com.jr.mapper.EmpMapper"><!-- 定義resultMap:映射Emp與Dept的一對一關聯 --><resultMap id="empWithDeptMap" type="emp"><!-- 映射Emp的基本字段:id標簽對應主鍵 --><id column="empno" property="empno"/><result column="ename" property="ename"/><result column="deptno" property="deptno"/><!-- 一對一關聯Dept:用<association> --><association property="dept" javaType="dept"> <!-- javaType:關聯實體類的類型(Dept) --><id column="d_deptno" property="deptno"/> <!-- 用別名避免字段名沖突 --><result column="dname" property="dname"/><result column="loc" property="loc"/></association></resultMap><!-- 關聯查詢SQL:多表連接,用別名區分字段 --><select id="selectEmpWithDept" resultMap="empWithDeptMap">select e.empno, e.ename, e.deptno, d.deptno as d_deptno, d.dname, d.locfrom emp einner join dept d on e.deptno = d.deptno</select>
</mapper>
- 測試代碼:
@Test
public void testSelectEmpWithDept() {SqlSession session = factory.openSession();EmpMapper empMapper = session.getMapper(EmpMapper.class);List<Emp> emps = empMapper.selectEmpWithDept();for (Emp emp : emps) {System.out.println("員工:" + emp.getEname() + ",部門:" + emp.getDept().getDname());}session.close();
}
文檔要點:<association>
標簽用于一對一關聯,javaType
屬性指定關聯實體類的類型,需用別名避免多表字段名沖突(如d.deptno as d_deptno
)。
2.3 一對多關聯查詢:部門→員工
場景:查詢部門信息時,同時查詢部門下的所有員工(一個部門有多個員工)。
實現步驟:
定義實體類:在Dept
類中添加List<Emp>
屬性,存儲關聯的員工列表。
public class Dept {private int deptno;private String dname;private String loc;private List<Emp> emps; // 一對多關聯:部門下的員工列表// getter/setter、toString()
}
編寫 Mapper 接口:
public interface DeptMapper {Dept selectDeptWithEmp(int deptno); // 查詢部門及下屬員工
}
配置 Mapper.xml:用<resultMap>
+<collection>
定義一對多關聯。
<mapper namespace="com.jr.mapper.DeptMapper"><!-- 定義resultMap:映射Dept與Emp的一對多關聯 --><resultMap id="deptWithEmpMap" type="dept"><!-- 映射Dept的基本字段 --><id column="deptno" property="deptno"/><result column="dname" property="dname"/><result column="loc" property="loc"/><!-- 一對多關聯Emp列表:用<collection> --><collection property="emps" ofType="emp"> <!-- ofType:集合中元素的類型(Emp) --><id column="e_empno" property="empno"/> <!-- 別名避免沖突 --><result column="e_ename" property="ename"/><result column="e_sal" property="sal"/></collection></resultMap><!-- 關聯查詢SQL:左連接查詢部門與員工 --><select id="selectDeptWithEmp" parameterType="int" resultMap="deptWithEmpMap">select d.deptno, d.dname, d.loc,e.empno as e_empno, e.ename as e_ename, e.sal as e_salfrom dept dleft join emp e on d.deptno = e.deptnowhere d.deptno = #{deptno}</select>
</mapper>
- 測試代碼:
@Test
public void testSelectDeptWithEmp() {SqlSession session = factory.openSession();DeptMapper deptMapper = session.getMapper(DeptMapper.class);Dept dept = deptMapper.selectDeptWithEmp(10);System.out.println("部門:" + dept.getDname());for (Emp emp : dept.getEmps()) {System.out.println(" 員工:" + emp.getEname() + ",薪資:" + emp.getSal());}session.close();
}
文檔要點:<collection>
標簽用于一對多關聯,ofType
屬性指定集合元素的類型(區別于javaType
,javaType
用于指定屬性類型,如List
)。
2.4 多表關聯查詢:用戶→訂單→訂單詳情→商品
場景:查詢用戶信息時,同時查詢用戶的所有訂單、每個訂單的詳情、每個詳情對應的商品(多表關聯:用戶 1:N 訂單 1:N 訂單詳情 1:1 商品)。
實現步驟:
定義實體類:逐層關聯(Users→Orders→OrderDetail→Items)。
// 用戶類:1個用戶對應多個訂單
public class Users {private int uid;private String uname;private List<Orders> orders; // 一對多關聯訂單// getter/setter
}// 訂單類:1個訂單對應多個詳情
public class Orders {private int oid;private String orderid;private List<OrderDetail> orderdetails; // 一對多關聯詳情// getter/setter
}// 訂單詳情類:1個詳情對應1個商品
public class OrderDetail {private int odid;private int itemsnum;private Items item; // 一對一關聯商品// getter/setter
}// 商品類
public class Items {private int iid;private String name;private double price;// getter/setter
}
配置 Mapper.xml:嵌套<collection>
和<association>
實現多表映射。
<mapper namespace="com.jr.mapper.UserMapper"><!-- 多表關聯resultMap:用戶→訂單→詳情→商品 --><resultMap id="userOrderDetailItemMap" type="users"><id column="uid" property="uid"/><result column="uname" property="uname"/><!-- 1:N:用戶→訂單 --><collection property="orders" ofType="orders"><id column="oid" property="oid"/><result column="orderid" property="orderid"/><!-- 1:N:訂單→訂單詳情 --><collection property="orderdetails" ofType="orderdetail"><id column="odid" property="odid"/><result column="itemsnum" property="itemsnum"/><!-- 1:1:訂單詳情→商品 --><association property="item" javaType="items"><id column="iid" property="iid"/><result column="name" property="name"/><result column="price" property="price"/></association></collection></collection></resultMap><!-- 多表關聯SQL:四表連接 --><select id="selectUserWithAll" resultMap="userOrderDetailItemMap">select u.uid, u.uname,o.oid, o.orderid,od.odid, od.itemsnum,i.iid, i.name, i.pricefrom users uinner join orders o on u.uid = o.useridinner join orderdetail od on o.orderid = od.orderidinner join items i on od.itemid = i.iid</select>
</mapper>
文檔要點:多表關聯需嵌套使用<collection>
(一對多)和<association>
(一對一),確保每層映射的column
與property
對應。
三、查詢緩存:MyBatis 的 “性能優化利器”
緩存是 “以空間換時間” 的優化手段,MyBatis 提供兩級緩存,減少數據庫訪問次數,提升高頻查詢的性能。
3.1 緩存的核心概念
MyBatis 的緩存分為兩級,作用域和生命周期不同:
- 一級緩存:
SqlSession
級別(本地緩存),默認開啟,無需配置; - 二級緩存:
Mapper
(namespace)級別(全局緩存),默認關閉,需手動配置; - 第三方緩存:如 Ehcache、Redis,用于分布式場景(多服務共享緩存)。
3.2 一級緩存:SqlSession 級別的本地緩存
核心特點:
- 作用域:同一個
SqlSession
(從openSession()
到close()
); - 實現:基于
PerpetualCache
(HashMap)存儲; - 失效場景:
- 調用
SqlSession.close()
; - 調用
SqlSession.commit()
/rollback()
(事務提交 / 回滾會清空緩存); - 執行相同 ID 的
insert
/update
/delete
(修改數據會清空緩存,避免臟讀); - 調用
SqlSession.clearCache()
(手動清空緩存)。
- 調用
實戰案例:
@Test
public void testFirstLevelCache() {SqlSession session = factory.openSession();EmpMapper empMapper = session.getMapper(EmpMapper.class);// 第一次查詢:執行SQL,結果存入一級緩存Emp emp1 = empMapper.selectEmpByNo(7369);System.out.println(emp1);// 第二次查詢:同一SqlSession,相同SQL,從緩存獲取(不執行SQL)Emp emp2 = empMapper.selectEmpByNo(7369);System.out.println(emp2);session.close();
}
日志輸出:僅第一次查詢執行 SQL,第二次從緩存獲取。
3.3 二級緩存:Mapper 級別的全局緩存
核心特點:
- 作用域:同一個
Mapper
(namespace),跨SqlSession
共享; - 存儲:默認存儲序列化后的 Java 對象(需實體類實現
Serializable
接口); - 配置步驟:需開啟全局開關 + Mapper 單獨配置。
配置步驟:
開啟全局二級緩存(SqlMapConfig.xml
):
<settings><setting name="cacheEnabled" value="true"/> <!-- 全局開關,默認true可省略 -->
</settings>
在 Mapper.xml 中開啟二級緩存:
<mapper namespace="com.jr.mapper.EmpMapper"><!-- 開啟二級緩存:默認使用PerpetualCache --><cache/><!-- 或配置緩存參數(如過期時間、最大容量) --><!--<cacheeviction="LRU" // 淘汰策略(LRU:最近最少使用)flushInterval="60000" // 60秒刷新一次緩存size="1024" // 最多緩存1024個對象readOnly="true"/> // 只讀模式(返回對象引用,性能高)--><select id="selectEmpByNo" parameterType="int" resultType="emp">select * from emp where empno = #{empno}</select>
</mapper>
實體類實現 Serializable 接口:
public class Emp implements Serializable { // 二級緩存需序列化private static final long serialVersionUID = 1L; // 序列化ID// 字段、getter/setter
}
實戰案例:
@Test
public void testSecondLevelCache() {// 第一個SqlSession:查詢后關閉,將數據刷入二級緩存SqlSession session1 = factory.openSession();EmpMapper empMapper1 = session1.getMapper(EmpMapper.class);Emp emp1 = empMapper1.selectEmpByNo(7369);System.out.println(emp1);session1.close(); // 關閉SqlSession,一級緩存數據刷入二級緩存// 第二個SqlSession:從二級緩存獲取數據(不執行SQL)SqlSession session2 = factory.openSession();EmpMapper empMapper2 = session2.getMapper(EmpMapper.class);Emp emp2 = empMapper2.selectEmpByNo(7369);System.out.println(emp2);session2.close();
}
文檔要點:二級緩存需通過session.close()
或session.commit()
將一級緩存數據刷入,否則無法共享。
關鍵配置:
- 禁用二級緩存:對實時性要求高的查詢(如秒殺商品庫存),添加
useCache="false"
:
<select id="selectEmpByNo" parameterType="int" resultType="emp" useCache="false">select * from emp where empno = #{empno}
</select>
- 刷新二級緩存:執行
insert
/update
/delete
后,默認清空二級緩存(避免臟讀),可通過flushCache="false"
關閉(不推薦):
<update id="updateEmp" parameterType="emp" flushCache="true"> <!-- 默認true,可省略 -->update emp set ename = #{ename} where empno = #{empno}
</update>
3.4 整合第三方緩存:Ehcache(分布式場景)
默認二級緩存是 “本地緩存”,分布式部署時(多臺服務器)緩存不共享,需整合分布式緩存框架(如 Ehcache)。
配置步驟:
添加 Maven 依賴:
<!-- MyBatis-Ehcache整合包 -->
<dependency><groupId>org.mybatis.caches</groupId><artifactId>mybatis-ehcache</artifactId><version>1.0.2</version>
</dependency><!-- Ehcache核心包 -->
<dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId><version>2.10.1</version>
</dependency>
添加 Ehcache 配置文件(ehcache.xml):
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"><!-- 緩存數據存儲路徑(磁盤) --><diskStore path="D:/mybatis-ehcache"/><!-- 默認緩存配置 --><defaultCachemaxElementsInMemory="1000" <!-- 內存最大緩存對象數 -->eternal="false" <!-- 不永久緩存 -->timeToIdleSeconds="120" <!-- 120秒未訪問則過期 -->timeToLiveSeconds="120" <!-- 120秒后過期 -->overflowToDisk="true"/> <!-- 內存滿時寫入磁盤 -->
</ehcache>
在 Mapper.xml 中指定 Ehcache 緩存:
<mapper namespace="com.jr.mapper.EmpMapper"><!-- 啟用Ehcache緩存 --><cache type="org.mybatis.caches.ehcache.EhcacheCache"/><!-- SQL語句... -->
</mapper>
文檔要點:Ehcache 支持內存 + 磁盤存儲,分布式部署時可配置集群,實現緩存共享。
四、總結:MyBatis 核心能力回顧與實踐建議
至此,MyBatis 從入門到精通系列三篇博客已全部完成,我們系統覆蓋了 MyBatis 的核心能力:
- 基礎層:框架概念、環境搭建(普通項目 + Maven);
- 核心層:三層架構、全局配置、Mapper 代理開發;
- 高級層:動態 SQL、關聯查詢、查詢緩存。
實踐建議:
- 動態 SQL:優先用
<where>``<set>
標簽簡化條件拼接,復雜場景用<trim>
,避免手動寫where 1=1
; - 關聯查詢:一對一用
<association>
,一對多用<collection>
,多表關聯需注意字段別名沖突; - 緩存優化:一級緩存默認開啟,二級緩存按需開啟(適合查詢多、修改少的場景),分布式項目整合 Ehcache/Redis;
- 開發規范:堅持 “Mapper 代理開發”,SQL 集中在 XML 中,通過
<sql>
片段復用代碼,提升維護性。
????????MyBatis 的核心優勢在于 “輕量、靈活、解耦”—— 既保留了 SQL 的靈活性,又簡化了數據映射與連接管理。掌握這些核心能力后,你不僅能應對企業級項目的持久層開發,更能在面試中從容應對 MyBatis 的高頻考點(如動態 SQL、緩存機制、關聯查詢)。后續可進一步學習 MyBatis-Plus(MyBatis 的增強工具,簡化 CRUD),但建議先夯實 MyBatis 基礎,再逐步拓展。