EJB 3.0 引入 遊離實體 概念,徹底改變了 EJB 2.x 時代的實體程設計範式。本文對比兩代規範,闡述遊離實體的特性、序列化傳輸優勢、以及如何取代傳統 Value Object (DTO) 模式,簡化應用程式架構。
當 交易範圍持久化上下文 或 擴展持久化上下文 結束,實體實例脫離容器管理,進入遊離狀態。關鍵特性:
EntityManager.merge() 將變更合併回資料庫。| 維度 | EJB 2.1 (Entity Bean) | EJB 3.0 (JPA Entity) |
|---|---|---|
| 程式模型 | 遠端/本地介面 Proxy,容器全權管理生命週期 | 純 Java 類別 (POJO),開發者直接操作實例 |
| 狀態存取 | 透過 getXxx()/setXxx() 遠端呼叫 | 直接存取欄位/屬性,本地記憶體速度 |
| 傳輸模式 | 需 Value Object (DTO) 複製狀態序列化 | 實體本身即可序列化,無需額外 DTO |
| 程式碼量 | 龐大:Home/Remote/Local/Bean/DTO/DAO... | 極簡:單一實體類別 + 註解/ORM XML |
| 學習曲線 | 陡峭:EJB 容器契約、部署描述檔、介面分離 | 平緩:標準 Java + JPA 註解 |
EJB 2.1 時代,為避免大量細粒度遠端呼叫(getFirstName(), getLastName()...),引入 Value Object (Data Transfer Object) 模式:
// EJB 2.1 Entity Bean
public class CustomerBean implements javax.ejb.EntityBean {
public CustomerValueObject getCustomerVO() {
return new CustomerValueObject(getFirstName(), getLastName(),
getStreet(), getCity(), getState(), getZip());
}
}
JPA 實體在脫離持久化上下文後,自動成為值物件:
getCustomerVO() 方法,直接傳遞實體實例。entity.setName("New") 即可,送回 em.merge(entity) 完成持久化。Serializable 並宣告 serialVersionUID,避免跨部署版本反序列化失敗。@OneToMany(fetch=LAZY)),序列化時會拋 LazyInitializationException。解法:FETCH=EAGER、EntityGraph、或傳輸前手動觸發載入。merge() 回傳新的受管實例,後續操作必須使用回傳實例,原遊離實體保持遊離。@Version 欄位,防止併發更新覆蓋。遊離實體是 EJB 3.0/JPA 簡化企業應用開發的關鍵創新:將「資料傳輸物件」內建於領域模型中,消除 DTO 映射層,讓開發者專注於業務邏輯而非基礎設施代碼。理解其生命週期、序列化約束與合併語義,是掌握現代 Java EE 持久層開發的核心能力。