Hibernate 允許在實體類別上以註解方式預先定義靜態查詢 (Named Query) 與原生 SQL 查詢 (Named Native Query),這些查詢在 SessionFactory 建立時即被解析並載入記憶體,全系統可重複使用,提升維護性與效能。
@Entity
@NamedQueries({
@NamedQuery(name = "query1", query = "select a from A a")
})
public class A { ... }
@Entity
@NamedQueries({
@NamedQuery(name = "query1", query = "select c from A c where c.id = :id"),
@NamedQuery(name = "query2", query = "select c from C c where c.id = :id")
})
public class A { ... }
透過 hints 屬性可指定查詢行為:
@NamedQuery(
name = "query2",
query = "select c from A c where c.id = ?",
hints = @QueryHint(name = "timeout", value = "20")
)
常用 Hint 參數:
| 參數名 | 說明 | 預設值 |
|---|---|---|
| cacheable | 是否啟用二級緩存 | false |
| cacheRegion | 指定緩存區域名稱 | otherwise |
| timeout | 查詢超時秒數 | - |
| fetchSize | JDBC 抓取筆數 | - |
| flushMode | 刷新模式 | - |
| cacheMode | 緩存模式 | - |
| readOnly | 載入實體設為唯讀 | false |
| comment | SQL 註釋 | - |
Query q = session.getNamedQuery("query1");
q.setParameter("id", 123);
List list = q.list();
@Entity
@NamedNativeQueries({
@NamedNativeQuery(
name = "nativesql1",
query = "select * from b where id > 1",
resultSetMapping = "sql1mapping"
)
})
@SqlResultSetMappings({
@SqlResultSetMapping(
name = "sql1mapping",
entities = @EntityResult(entityClass = B.class)
)
})
public class B { ... }
使用 fields 屬性指定欄位對應:
@Entity
@NamedNativeQueries({
@NamedNativeQuery(
name = "nativesql1",
query = "select bname from b where id > 1",
resultSetMapping = "sql1mapping"
)
})
@SqlResultSetMappings({
@SqlResultSetMapping(
name = "sql1mapping",
entities = @EntityResult(
entityClass = B.class,
fields = @FieldResult(name = "bname", column = "bname")
)
)
})
public class B { ... }
Query q = session.getNamedQuery("nativesql1");
List list = q.list();
for (B b : list) {
System.out.println(b.getBname()); // 正常
// System.out.println(b.getId()); // 拋出異常:Column 'id1_0_' not found
}
關鍵提醒: 若 ResultSetMapping 僅包含部分欄位,實體中未映射的欄位 (如 id) 存取時將拋出異常,建議查詢時包含主鍵或使用 DTO 承接。
善用 @NamedQuery 與 @NamedNativeQuery 可將查詢邏輯集中管理,配合 Hint 微調行為,並透過 @SqlResultSetMapping 靈活處理原生 SQL 結果映射,是大型專案優化資料存取層的關鍵技巧。