| 維度 | HQL (Hibernate Query Language) | Criteria Query |
|---|---|---|
| 風格 | 類 SQL 字串,面向物件 | 程式化 API,型別安全 |
| 編譯時檢查 | 無(執行時解析) | 有(IDE 智慧提示、重構支援) |
| 動態查詢構建 | 字串拼接困難、易注入 | 條件組合靈活(Criterion、Projections) |
| 投影/聚合 | SELECT 子句直觀 | Projections API 較冗長 |
| 分頁/排序 | Query.setFirstResult/MaxResults、ORDER BY | Criteria.setFirstResult/MaxResults、Order.asc/desc |
| 適用場景 | 靜態、複雜、報表類查詢 | 動態條件、搜尋表單、通用 DAO |
FROM Cat -- 所有 Cat 實例
FROM Cat AS cat -- 別名(建議)
FROM Cat cat -- AS 可省略
FROM Cat cat, Dog dog -- 笛卡兒積
FROM Cat cat INNER JOIN cat.kittens kitten -- 關聯導航
INNER JOIN -- 僅匹配雙方
LEFT OUTER JOIN -- 左表全保留,右表無匹配則 null
RIGHT OUTER JOIN-- 右表全保留
FULL JOIN -- 雙方全保留(資料庫支援度有限)
範例:員工-部門
-- INNER JOIN:僅有部門的員工
SELECT e.id, e.name, d.name FROM Employee e JOIN e.department d
-- LEFT JOIN:所有員工,無部門者 department 欄位為 null
SELECT e.id, e.name, d.name FROM Employee e LEFT JOIN e.department d
SELECT e.name FROM Employee e WHERE e.name LIKE 'J%'
SELECT e.id, e.name, d.id, d.name FROM Employee e RIGHT JOIN e.department d
SELECT COUNT(DISTINCT e.name), COUNT(e) FROM Employee e
SELECT AVG(e.salary), MAX(e.salary) FROM Employee e GROUP BY e.department
FROM Animal a -- 回傳 Animal 及所有子類 (Cat, Dog...)
FROM java.lang.Object o-- 回傳所有持久化實體(慎用,效能極差)
-- 位置參數
List list = session.find("FROM Employee e WHERE e.name = ?", name, Hibernate.STRING);
-- 命名參數(推薦,可讀性佳)
Query q = session.createQuery("FROM Employee e WHERE e.name = :name");
q.setString("name", "Jplateau");
Iterator it = q.iterate();
FROM Cat fatcat WHERE fatcat.weight > (SELECT AVG(cat.weight) FROM DomesticCat cat)
Criteria criteria = session.createCriteria(User.class);
criteria.add(Expression.eq("name", "Erica"));
criteria.add(Expression.eq("sex", Integer.valueOf(1)));
// 動態條件組合
if (searchForm.getName() != null) {
criteria.add(Expression.like("name", "%" + searchForm.getName() + "%"));
}
if (searchForm.getMinAge() != null) {
criteria.add(Expression.ge("age", searchForm.getMinAge()));
}
// 投影與聚合
criteria.setProjection(Projections.projectionList()
.add(Projections.count("id"), "total")
.add(Projections.groupProperty("department"), "dept"));
// 分頁排序
criteria.addOrder(Order.desc("createTime"));
criteria.setFirstResult(0);
criteria.setMaxResults(20);
List results = criteria.list();
<hibernate-mapping>
<query name="findRichUsers">
FROM User u WHERE u.balance > :minBalance
</query>
</hibernate-mapping>
// 使用
Query q = session.getNamedQuery("findRichUsers");
q.setParameter("minBalance", 10000);
SQLQuery sql = session.createSQLQuery("SELECT * FROM user WHERE status = ?")
.addEntity(User.class)
.setInteger(0, 1);
List users = sql.list();
FROM java.lang.Object 全表掃描fetch="join" 或 LEFT JOIN FETCH 解決 N+1 問題ScrollableResults / Stream 串流處理@BatchSize(size=20) 或 hibernate.default_batch_fetch_sizeCriteriaBuilder / CriteriaQuery (JPA 標準) 取代舊 Criteria APIJpaSpecificationExecutor + Specification 實現型別安全動態查詢HQL 適合靜態、複雜、報表查詢,可讀性高;Criteria 適合動態條件組合、通用搜尋元件。現代專案建議採用 JPA CriteriaBuilder 或 QueryDSL,兼得型別安全與表達力。理解兩者底層皆轉譯為 SQL,善用 show_sql=true、format_sql=true 分析執行計畫,是效能調優關鍵。