首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Hibernate Session.load() vs get() 核心差異深度解析

     編輯:Java 相關知識

在 Hibernate 資料存取操作中,Session.load() 與 Session.get() 是最常用的兩種載入實體方法。雖然都能根據識別值取得物件,但它們在延遲載入支援、無資料時行為、SQL 發送時機上有本質差異。選錯方法可能導致效能問題或執行期例外。

核心差異快速對照

特性get()load()
延遲載入不支援支援 (回傳 Proxy)
查無資料回傳 null拋出 ObjectNotFoundException
SQL 發送時機立即執行首次存取屬性時
回傳型別實體實例Proxy 代理物件

get() 立即載入範例

public void testGetMethod() {
    Session session = null;
    try {
        session = HibernateUtils.getSession();
        session.beginTransaction();

        // 立即發送 SELECT SQL
        User user = (User) session.get(User.class, "402880d01b9bf210011b9bf2c2ff0002");
        System.out.println("user.name=" + user.getName()); // 即使不呼叫這行,SQL 已執行

        user.setName("張三");
        session.getTransaction().commit();
    } catch (Exception e) {
        e.printStackTrace();
        session.getTransaction().rollback();
    } finally {
        HibernateUtils.closeSession(session);
    }
}

行為特徵: 第 8 行執行時,無論後續是否使用物件,Hibernate 都會立即查詢資料庫。查無資料回傳 null,需自行判斷避免 NPE。

load() 延遲載入範例

public void testLoadMethod() {
    Session session = null;
    try {
        session = HibernateUtils.getSession();
        session.beginTransaction();

        // 不發送 SQL,回傳 Proxy 代理物件
        User user = (User) session.load(User.class, "402880d01b9bf210011b9bf2b2ff0002");
        
        // 這行觸發真實 SQL 查詢
        System.out.println("user.name=" + user.getName());
        
        user.setName("李四");
        session.getTransaction().commit();
    } catch (Exception e) {
        e.printStackTrace();
        session.getTransaction().rollback();
    } finally {
        HibernateUtils.closeSession(session);
    }
}

行為特徵: 第 10 行僅建立 Proxy 物件,不查資料庫。第 11 行首次存取屬性時才發送 SQL。若 ID 不存在,存取屬性時拋出 ObjectNotFoundException。

Proxy 代理機制原理

load() 利用 CGLIB/ByteBuddy 動態代理 建立實體子類別實例:

  • Proxy 物件持有識別值與 Session 參考
  • 首次呼叫非 ID 的 getter 方法時,觸發攔截器載入真實資料
  • 載入完成後,Proxy 內部委派給真實實體

選擇指南

✅ 使用 get() 的場景:

  • 不確定資料是否存在,需根據回傳值判斷邏輯分支
  • 需要立即存取物件屬性(如建構 DTO、序列化傳輸)
  • 批次處理中,避免大量 Proxy 物件佔用記憶體

✅ 使用 load() 的場景:

  • 確定資料必須存在(如外鍵關聯、父實體載入子集合)
  • 只需設定關聯關係,不需存取其他屬性(如 order.setCustomer(session.load(Customer.class, id)))
  • 效能敏感場景,避免不必要的資料庫往返

除錯技巧

在 IDE 設定斷點觀察變數變化:

  • get():執行行後,變數立即顯示實體欄位值
  • load():執行行後,變數顯示為 User_$$_javassist_123 (Proxy 類別),展開可見 handler 欄位持有識別值

掌握兩者差異,能讓資料存取層更精準、更高效。

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