HQL (Hibernate Query Language) 針對實體物件與屬性操作,而非資料表與欄位。最終由 Hibernate 轉換為 SQL 執行,具備資料庫可攜性與緩存策略優勢。
// 完整載入實體
FROM Employee
FROM com.company.model.Employee // 全限定名
// 別名 (AS 可省略)
FROM Employee AS e
FROM Employee e
// 選取特定屬性 (回傳 List<Object[]> 或 List<String>)
SELECT e.firstName, e.salary FROM Employee e
// 條件過濾
FROM Employee e WHERE e.salary > 5000 AND e.department.name = 'IT'
// 排序
FROM Employee e ORDER BY e.salary DESC, e.hireDate ASC
// 分組聚合
SELECT e.department.name, AVG(e.salary), COUNT(*)
FROM Employee e GROUP BY e.department.name
HAVING COUNT(*) > 5
// 命名參數 (推薦)
String hql = "FROM Employee e WHERE e.salary > :minSal AND e.department = :dept";
Query query = session.createQuery(hql);
query.setParameter("minSal", 5000);
query.setParameter("dept", deptEntity);
// 位置參數 (從 0 開始)
query.setParameter(0, 5000);
Query query = session.createQuery("FROM Employee e ORDER BY e.id");
query.setFirstResult(0); // 起始索引
query.setMaxResults(20); // 每頁筆數
List<Employee> page = query.list();
// 更新
String hql = "UPDATE Employee e SET e.salary = e.salary * 1.1 WHERE e.department.id = :deptId";
int updated = session.createQuery(hql)
.setParameter("deptId", 1)
.executeUpdate();
// 刪除
String hql = "DELETE FROM Employee e WHERE e.status = 'LEFT'";
int deleted = session.createQuery(hql).executeUpdate();
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> root = cq.from(Employee.class);
// 選取全部
cq.select(root);
// 條件謂詞
Predicate salaryGt = cb.gt(root.get("salary"), 5000);
Predicate deptEq = cb.equal(root.get("department").get("id"), 1);
cq.where(cb.and(salaryGt, deptEq));
// 排序
cq.orderBy(cb.desc(root.get("salary")), cb.asc(root.get("hireDate")));
// 執行
List<Employee> result = session.createQuery(cq).getResultList();
| 方法 | 對應 SQL | 範例 |
|---|---|---|
eq | = | Restrictions.eq("status", "ACTIVE") |
gt/ge/lt/le | > / ≥ / < / ≤ | Restrictions.gt("age", 18) |
like/ilike | LIKE (不分大小寫) | Restrictions.like("name", "John%") |
between | BETWEEN | Restrictions.between("salary", 3000, 8000) |
in/notIn | IN / NOT IN | Restrictions.in("id", ids) |
isNull/isNotNull | IS NULL | Restrictions.isNull("deletedAt") |
and/or | AND / OR | Restrictions.or(c1, c2) |
CriteriaQuery<Object[]> cq = cb.createQuery(Object[].class);
Root<Employee> root = cq.from(Employee.class);
// 聚合函數
cq.multiselect(
cb.count(root), // 總筆數
cb.avg(root.get("salary")), // 平均薪資
cb.max(root.get("salary")), // 最高薪資
cb.sum(root.get("salary")), // 薪資總和
cb.countDistinct(root.get("dept")) // 部門數
);
TypedQuery<Employee> query = session.createQuery(cq);
query.setFirstResult(0);
query.setMaxResults(10);
JOIN FETCH (HQL) 或 fetch() (Criteria) 解決 N+1 問題uniqueResult() / getSingleResult() 配合異常處理query.setLockMode(LockMode.PESSIMISTIC_WRITE) 實現悲觀鎖query.setCacheable(true) 配合二級快取createNativeQuery() 配合 @SqlResultSetMappingHQL 適合靜態、可讀性要求高的查詢;Criteria API 勝在動態組裝、型別安全、IDE 重構支援。現代 Hibernate (5.2+) 推薦使用 JPA 標準 CriteriaBuilder,舊版 Criteria 逐步淘汰。掌握兩者並根據場景選擇,是高效資料存取的關鍵。