MyBatis 從入門到精通(第三篇)—— 動態 SQL、關聯查詢與查詢緩存

????????在前兩篇博客中,我們掌握了 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關鍵字;
  • 自動去掉第一個條件前的ANDOR
  • 若內部無滿足條件的<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 &lt;= #{sal} <!-- XML中“<”需轉義為“&lt;” --></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>
  1. 測試代碼
@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>
  1. 測試代碼
@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屬性指定集合元素的類型(區別于javaTypejavaType用于指定屬性類型,如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>(一對一),確保每層映射的columnproperty對應。

三、查詢緩存:MyBatis 的 “性能優化利器”

緩存是 “以空間換時間” 的優化手段,MyBatis 提供兩級緩存,減少數據庫訪問次數,提升高頻查詢的性能。

3.1 緩存的核心概念

MyBatis 的緩存分為兩級,作用域和生命周期不同:

  • 一級緩存SqlSession級別(本地緩存),默認開啟,無需配置;
  • 二級緩存Mapper(namespace)級別(全局緩存),默認關閉,需手動配置;
  • 第三方緩存:如 Ehcache、Redis,用于分布式場景(多服務共享緩存)。

3.2 一級緩存:SqlSession 級別的本地緩存

核心特點:
  • 作用域:同一個SqlSession(從openSession()close());
  • 實現:基于PerpetualCache(HashMap)存儲;
  • 失效場景
    1. 調用SqlSession.close()
    2. 調用SqlSession.commit()/rollback()(事務提交 / 回滾會清空緩存);
    3. 執行相同 ID 的insert/update/delete(修改數據會清空緩存,避免臟讀);
    4. 調用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 的核心能力:

  1. 基礎層:框架概念、環境搭建(普通項目 + Maven);
  2. 核心層:三層架構、全局配置、Mapper 代理開發;
  3. 高級層:動態 SQL、關聯查詢、查詢緩存。
實踐建議:
  1. 動態 SQL:優先用<where>``<set>標簽簡化條件拼接,復雜場景用<trim>,避免手動寫where 1=1
  2. 關聯查詢:一對一用<association>,一對多用<collection>,多表關聯需注意字段別名沖突;
  3. 緩存優化:一級緩存默認開啟,二級緩存按需開啟(適合查詢多、修改少的場景),分布式項目整合 Ehcache/Redis;
  4. 開發規范:堅持 “Mapper 代理開發”,SQL 集中在 XML 中,通過<sql>片段復用代碼,提升維護性。

????????MyBatis 的核心優勢在于 “輕量、靈活、解耦”—— 既保留了 SQL 的靈活性,又簡化了數據映射與連接管理。掌握這些核心能力后,你不僅能應對企業級項目的持久層開發,更能在面試中從容應對 MyBatis 的高頻考點(如動態 SQL、緩存機制、關聯查詢)。后續可進一步學習 MyBatis-Plus(MyBatis 的增強工具,簡化 CRUD),但建議先夯實 MyBatis 基礎,再逐步拓展。

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

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

相關文章

Linux內核中IPv4的BEET模式封裝機制解析

引言 在Linux網絡棧中,IPSec提供了網絡層的數據加密和認證服務。傳統的IPSec支持兩種模式:傳輸模式(Transport Mode)和隧道模式(Tunnel Mode)。然而,這兩種模式各有優缺點:傳輸模式開銷小但無法隱藏原始IP頭;隧道模式提供完全封裝但增加了開銷。 BEET(Bound End-to…

設計模式——創建型模式

什么是設計模式&#xff1f;設計模式是軟件工程中解決常見問題的經典方案&#xff0c;它們代表了最佳實踐和經驗總結。通過使用設計模式&#xff0c;開發者可以創建更加靈活、可維護和可擴展的代碼結構。設計模式不是具體的代碼實現&#xff0c;而是針對特定問題的通用解決方案…

我愛學算法之—— 位運算(上)

常見位運算 對于位運算&#xff1a; &&#xff1a;按位與&#xff0c;有0則0。 |&#xff1a;按位或&#xff0c;有1則1。 ^&#xff1a;按位異或&#xff0c;相同為0、不同為1。&#xff08;無進位相加&#xff09; ~&#xff1a;二進制位按位取反。 對于位運算的常見使用…

智能語音系統

智能語音系統通過技術手段讓機器能夠“聽懂”、“理解”并“回應”人類的語音&#xff0c;是實現人機交互的關鍵技術之一。下面我將為你梳理智能語音系統的核心組成部分、工作原理、應用場景以及面臨的挑戰。&#x1f9e0; 核心技術與工作原理智能語音系統之所以能實現人機交互…

水泵自動化遠程監測與控制的御控物聯網解決方案

一、行業背景與痛點分析水泵作為工業生產、農業灌溉、城市供水等領域的核心設備&#xff0c;其運行效率直接影響系統穩定性與運營成本。然而&#xff0c;傳統管理模式存在三大核心痛點&#xff1a;人工巡檢低效&#xff1a;偏遠地區水泵分布分散&#xff0c;依賴人工定期巡檢&a…

Python實現點云法向量各種方向設定

本次我們分享點云法向量定向的四種方法&#xff0c;分別是XYZ軸、相機位置、最小生成樹(MST)和質心設定方法。通常出現在三維點云處理、三維重建、計算機視覺或圖形學中&#xff0c;需要估計點云的法向量方向。它們的核心任務是&#xff1a;在已知點坐標和局部幾何結構&#xf…

騰訊云智能體開發平臺

提供全球領先的云計算服務騰訊云&#xff0c;騰訊集團傾力打造的云計算品牌&#xff0c;面向全世界各個國家和地區的政府機構、企業組織和個人開發者&#xff0c;提供全球領先的云計算、大數據、人工智能等技術產品與服務&#xff0c;以卓越的科技能力打造豐富的行業解決方案&a…

css flex布局,設置flex-wrap:wrap換行后,如何保證子節點被內容撐高后,每一行的子節點高度一致。

flex布局&#xff0c;設置flex-wrap&#xff1a;wrap換行后&#xff0c;如何保證子節點被內容撐高后&#xff0c;每一行的子節點高度一致。核心&#xff1a;需要設置父節點和子節點&#xff1a;align-items: stretch&#xff0c;兩個都要。代碼&#xff1a;<div class"…

Nginx_Tomcat綜合案例

要求 需求&#xff1a;通過 nginx 來代理兩個 tomcat 服務器&#xff08;反向代理&#xff09;&#xff0c;然后通過 https://www.nginx.com 來進行訪問。主機名IP軟件nginx192.168.30.10nginxtomcat1192.168.30.11java&#xff0c;tomcattomcat2192.168.30.12java&#xff0c;…

【Vue2手錄12】單文件組件SFC

一、知識回顧-Vue2項目基礎操作與環境配置 1.1 項目啟動 項目打開方式&#xff1a;直接將項目文件夾&#xff08;如my-app&#xff09;拖拽到 Visual Studio Code&#xff08;推薦編輯器&#xff09;&#xff0c;避免拖拽父級文件夾&#xff0c;防止路徑混亂。啟動命令&#xf…

VS2022下載+海康SDK環境配置實現實時預覽

一.VS2022下載去官網下載就可以了&#xff1a;https://visualstudio.microsoft.com/zh-hans/vs/下載Community版本是免費的。&#xff08;2&#xff09;下載后得安裝包VisualStudioSetup.exe打開&#xff1a;點擊繼續等待下載完成&#xff0c;出現如下界面&#xff0c;這里是選…

YOLO 模型從 PyTorch 轉換為 ONNX 并優化

YOLO 模型從 PyTorch 轉換為 ONNX 并優化 在深度學習部署中&#xff0c;ONNX&#xff08;Open Neural Network Exchange&#xff09; 已成為跨框架與跨平臺的標準格式。我們經常需要將 YOLOv8 在 PyTorch 中訓練好的模型轉換為 ONNX&#xff0c;并進行優化&#xff0c;以便在 …

推進新型信息基礎設施建設發展:蜂窩模組行業迎來結構性機遇

工信部副部長張云明在2025年9月9日國新辦新聞發布會上明確表示&#xff0c;將"扎實推進新型信息基礎設施建設發展"&#xff0c;并重點強調"打造新型工業網絡&#xff0c;推進蜂窩車聯網部署" 。這一政策表態對蜂窩模組行業產生深遠影響&#xff0c;將推動行…

返利app排行榜的緩存更新策略:基于過期時間與主動更新的混合方案

返利app排行榜的緩存更新策略&#xff1a;基于過期時間與主動更新的混合方案 大家好&#xff0c;我是阿可&#xff0c;微賺淘客系統及省賺客APP創始人&#xff0c;是個冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 在返利APP中&#xff0c;“熱門商品排行榜”“用…

科技信息差(9.12)

AI量子計算重塑藥物研發&#xff1a;技術融合路徑與產業革命一、引言&#xff1a;技術融合的顛覆性機遇2025年9月&#xff0c;AI藥物研發公共服務平臺正式上線&#xff0c;宣稱可將新藥上市時間縮短近半1。與此同時&#xff0c;量子計算與AI的跨界合作在KRAS抑制劑開發中取得突…

Java 分布式緩存實現:結合 RMI 與本地文件緩存

目錄 一、核心思路 二、項目結構說明 2.1 服務端項目結構&#xff08;IDEA&#xff09; 2.2 客戶端項目結構&#xff08;Eclipse&#xff09; 三、服務端實現&#xff08;IDEA&#xff09; 3.1 數據庫訪問層 3.2 遠程接口定義 3.3 遠程服務實現 3.4 服務端啟動類 四、…

Electron第一個應用

1、安裝node nodeJS下載 2、下載完成&#xff0c;需要配置環境。 寫道path路徑 、 3、安裝完成&#xff0c;查看版本 npm -v4、 配置cnpm npm install -g cnpm --registryhttps://registry.npmmirror.com5、參考Electron 寫&#xff1a; Electron第一個程序hello 6、安裝…

React 原理篇 - React 新架構深度解析

使用過 React v16 之前版本的開發者或許都經歷過這樣的場景&#xff1a;當頁面包含復雜組件或大量列表時&#xff0c;輸入框打字會卡頓&#xff0c;滾動會不流暢。這些體驗問題的背后&#xff0c;往往與 React 的渲染機制密切相關。2017 年 React v16 推出的 Fiber 架構&#x…

【JavaSE五天速通|第三篇】常用API與日期類篇

適合有其他語言基礎想快速入門JavaSE的。用的資料是 Java入門基礎視頻教程 &#xff0c;從中摘取了筆者認為與其他語言不同或需要重點學習的內容 常用API與日期類只需要有印象即可&#xff0c;用到了再來這查 day04 常用API 一、StringBuilder類 StringBuilder代表可變字符…

K8s學習筆記(二) Pod入門與實戰

1 K8s核心資源Pod 1.1 Pod是什么&#xff1f; 官方文檔&#xff1a;Pod | Kubernetes Pod 是 Kubernetes&#xff08;k8s&#xff09;中最小的部署與調度單元&#xff0c;并非直接運行容器&#xff0c;而是對一個或多個 “緊密關聯” 容器的封裝。 核心特點可簡單總結為 3 …