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

Hibernate 查詢策略深度對比:HQL 與 Criteria (QBC) 選型指南

     編輯:Java 相關知識

Hibernate 提供 HQL(物件導向查詢語言)與 Criteria API(QBC,Query By Criteria)兩種主流查詢方式。兩者各有優勢,盲目偏好其中一種會限制開發效率。本文從可讀性、動態組裝、多表關聯、效能調優、維護性五大維度深度對比,給出實戰選型建議。

基礎語法對比

簡單條件查詢

// HQL
Query q = session.createQuery("from User u where u.id=2 and u.age=21 and u.name like 'J%'");
List list = q.list();

// Criteria
Criteria c = session.createCriteria(User.class);
list = c.add(Restrictions.eq("id", 2))
        .add(Restrictions.eq("age", 21))
        .add(Restrictions.like("name", "J%"))
        .list();

Criteria 程式化構建,免拼接字串,編譯期檢查屬性名(搭配 Metamodel 更強)。

多表關聯查詢

// HQL:需精通關聯路徑,字串長難維護
"from User u join u.accounts a where a.id=112546 and a.startDate='2008-8-30' and a.money=1000"

// Criteria:物件導向導航
Criteria c = session.createCriteria(User.class);
c.add(Restrictions.eq("id", 2))
 .createCriteria("accounts", "a")           // 關聯到 Account
 .add(Restrictions.eq("a.id", 112546))
 .add(Restrictions.eq("a.startDate", date))
 .add(Restrictions.eq("a.money", 1000));

Criteria 在動態關聯(如可選關聯條件)極具優勢。

五大維度深度評估

維度HQLCriteria (QBC)
靜態/簡單查詢✅ 簡潔直觀,類 SQL 易上手稍繁瑣,需建立 Criteria 物件
動態條件組裝❌ 字串拼接易錯、防注入麻煩✅ 程式化 add(),條件可選、可迴圈
多表關聯/投影⚠️ 需手寫 join path,投影需 select new DTO✅ createCriteria/Projection 原生支援
效能調優✅ 可直接複製到 DB 執行計畫分析⚠️ 需開啟 show_sql 觀察生成 SQL
類型安全/重構❌ 字串屬性名,重構易漏改✅ 搭配 Metamodel/Static Metamodel 編譯期檢查
分頁/排序setFirstResult/setMaxResults 同樣支援addOrder/orderBy 同樣支援
原生 SQL 映射createSQLQuery + addEntity/ResultTransformercreateSQLQuery + setResultTransformer

實戰選型建議

首選 HQL 场景

  • 固定、較複雜的報表查詢(含子查詢、窗口函數、CTE)。
  • 需 DBA 協助調優,直接拿 SQL 執行計畫分析。
  • 團隊更熟悉 SQL 思維,維護成本較低。

首選 Criteria 场景

  • 動態查詢頁面:用戶可任意組合篩選條件(電商後台、報表配置)。
  • 條件中包含可選關聯(如:可選加入「訂單」表篩選)。
  • 大量使用投影、聚合、分組的統計查詢。
  • 追求類型安全,配合 JPA Static Metamodel(User_.name)。

混合策略(推薦)

// Repository 方法簽名統一回傳 List 或 Page
public List findByDynamicSpec(UserSpec spec) {
    if (spec.isSimple()) return hqlTemplate.query(spec.toHql(), spec.getParams());
    else return criteriaBuilder.build(spec).list();
}

將簡單查詢走 HQL,複雜動態查詢走 Criteria,Repository 封裝細節,上層無感知。

避坑指南

  • 關聯懶載入陷阱:HQL/Criteria 預設不會自動 join fetch,導致 N+1 問題。需顯式 join fetch 或 setFetchMode(FetchMode.JOIN)。
  • Criteria 去重:一對多關聯會導致主表重複行,需 setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)。
  • 大量資料分頁:offset/limit 深分頁效能差,改用 Keyset Pagination(where id > lastId order by id limit 20)。
  • 不可變實體:查詢唯讀場景加 setReadOnly(true) 或 @Transactional(readOnly=true) 關閉脏檢查提升效能。

結論

HQL 與 Criteria 不是非此即彼。成熟團隊應**兩者並用**,在 Repository 層封裝細節,根據查詢特性選擇最適工具。核心原則:靜態用 HQL,動態用 Criteria;調優看 SQL,重構靠類型安全。

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