首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> DB2 資料庫 >> DB2 教學

MyBatis 延遲加載深度解析:原理、配置與調試實戰

     編輯:DB2 教學

MyBatis 延遲加載深度解析:原理、配置與調試實戰

業務場景

查詢訂單列表,訂單詳情(商品明細)非必須即時展示。若一次性 JOIN 兩表查詢,數據量大時極其消耗資源。延遲加載允許先查訂單,用戶點擊展開時再按需查詢詳情,實現「按需加載、分散壓力」。

核心配置

<settings>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="aggressiveLazyLoading" value="false"/>
</settings>
  • lazyLoadingEnabled=true:全局啟用延遲加載。
  • aggressiveLazyLoading=false:關鍵設置!true 時調用任意 getter 會觸發所有延遲屬性加載;false 時僅調用具體延遲屬性的 getter 才觸發加載(推薦)。

Mapper XML 改造

1. 拆分 SQL

<!-- 只查訂單主表 -->
<select id="findOrders" resultMap="orderResultMap">
  SELECT * FROM orders
</select>

<!-- 按訂單 ID 查詳情 -->
<select id="findDetailsByOrderId" resultType="OrderDetailCustom">
  SELECT * FROM orderdetail WHERE orders_id = #{orderId}
</select>

2. resultMap 配置關聯

<resultMap id="orderResultMap" type="OrdersCustom">
  <id column="id" property="id"/>
  <result column="user_id" property="userId"/>
  <result column="number" property="number"/>
  <result column="createtime" property="createTime"/>
  <result column="note" property="note"/>

  <!-- 延遲加載詳情列表 -->
  <collection property="orderDetails" 
              column="id" 
              ofType="OrderDetailCustom" 
              select="com.mapper.OrderDetailMapper.findDetailsByOrderId">
  </collection>
</resultMap>

關鍵屬性解析:

  • property:實體類中對應的集合屬性名(List orderDetails)。
  • column:主查詢結果中作為參數傳遞的列(訂單 id)。
  • ofType:集合泛型類型(一對多用 ofType)。
  • select:具體加載 SQL 的 Mapper 方法全限定名。

實體類設計

public class OrdersCustom extends Orders {
    private List orderDetails;  // 延遲加載屬性
    // getter/setter
}

public class OrderDetailCustom extends OrderDetail {
    private ItemsCustom items;  // 可再嵌套一對一
    // getter/setter
}

調試驗證延遲加載效果

@Test
public void testLazyLoading() {
    OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
    List orders = mapper.findOrders();  // 斷點 1
    
    // 此時控制台只打印「SELECT * FROM orders」
    // 未執行任何 findDetailsByOrderId 查詢
    
    System.out.println(orders);  // 斷點 2:僅觸發 toString(),不調用 orderDetails getter
    
    // 真正訪問詳情時才觸發查詢
    for (OrdersCustom order : orders) {
        List details = order.getOrderDetails();  // 此處發起 SQL
        System.out.println(details);
    }
}

控制台 SQL 輸出驗證

進階技巧與避坑

  1. N+1 問題:列表頁若需顯示每筆訂單的詳情摘要,延遲加載會產生 N+1 條 SQL。解決:列表頁改用 JOIN 或批量預加載(select * from orderdetail where orders_id in (...))。
  2. 序列化陷阱:返回 JSON 給前端時,Jackson 會調用所有 getter 導致全量加載。解決:DTO 層剝離,或 @JsonIgnore 標記延遲屬性。
  3. 事務邊界:延遲加載 SQL 默認在新事務中執行,若需同一事務,配置 SqlSessionFactory 共享連接或手動管理事務。
  4. 嵌套延遲:OrderDetailCustom.items 可再配置 <association select="..."/> 實現多級延遲,屬性區別:一對一用 javaType,一對多用 ofType。

原理剖析

MyBatis 通過 CGLIB 動態代理 生成實體類代理對象,攔截延遲屬性的 getter 調用,執行對應的 select 映射語句,將結果填充到屬性並返回。代理對象持有 SqlSession 引用,確保數據庫連接可用。

合理使用延遲加載,能在複雜對象圖查詢中實現「查詢拆分、按需執行、資源平滑」,是 MyBatis 應對高並發讀場景的利器。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved