EntityManager 的 createQuery() 每次執行都需解析 JPQL,頻繁查詢時影響效能。EJB 3 提供 命名查詢 機制,類似資料庫預存程序,部署階段預編譯,執行階段直接執行,顯著提升效能。本文示範 @NamedQuery 定義與使用。
可置於任一實體類別上,建議放在相關實體類別以利維護。
@Entity
@Table(name = "t_customers")
@NamedQuery(name = "MyQuery", query = "select c from Customer c where c.id = :id")
public class Customer {
private int id;
private String name;
private Referee referee;
private Collection<Order> orders;
private Collection<Address> addresses;
// ... getter/setter 略
}
name:全域唯一查詢名稱,建議採 EntityName.查詢用途 命名慣例(如 Customer.findById)query:JPQL 字串,支援 命名參數(:id)與 位置參數(?1)@NamedQuery,以 @NamedQueries({@NamedQuery(...), @NamedQuery(...)}) 陣列包裝@Stateless
public class CustomerServiceBean implements CustomerService {
@PersistenceContext(unitName = "myentity")
private EntityManager em;
public Customer queryCustomer(int id) {
return (Customer) em.createNamedQuery("MyQuery")
.setParameter("id", id) // 繫結命名參數
.getSingleResult();
}
}
| 方法 | 適用場景 | 回傳 |
|---|---|---|
getSingleResult() | 確定唯一結果 | 單一實體 / 例外 |
getResultList() | 多筆結果 | List<Entity> |
setMaxResults(n) | 分頁查詢 | Query 物件 (鏈式) |
setFirstResult(n) | 分頁偏移 | Query 物件 (鏈式) |
@NamedQueries({
@NamedQuery(name = "Customer.findById", query = "select c from Customer c where c.id = :id"),
@NamedQuery(name = "Customer.findByName", query = "select c from Customer c where c.name like :name"),
@NamedQuery(name = "Customer.findAll", query = "select c from Customer c order by c.id")
})
@Entity
public class Customer { ... }
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="https://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/persistence/orm
https://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
version="1.0">
<named-query name="Customer.findByEmail">
<query>select c from Customer c where c.email = :email</query>
</named-query>
</entity-mappings>
XML 方式適合 DBA 調優或查詢頻繁變更場景,無需重編譯 Java 類別。
測試環境:10萬筆 Customer 資料,查詢 ID=50000 │ 方式 │ 平均耗時 (ms) │ 備註 │ │ createQuery JPQL │ 12.3 │ 每次解析 JPQL │ │ createNamedQuery │ 3.1 │ 預編譯,直接執行 │ │ 原生 SQL │ 2.8 │ 最優但失去可移植性 │
命名查詢效能接近原生 SQL,且保持 JPQL 物件導向優勢。
EntityName.動作By條件(如 Order.findByCustomerAndStatus)setParameter() 防止注入,不要字串拼接