自從起草EJB 3.0的規範開始,無論是在用戶端還是在伺服器端的應用程式裡,Java的類就一直有一種單一的、標準的persistence機制。Java 5的Annotations(批註)功能很容易使用。本文將介紹如何使用它。
保持Java類;現在已經有很多方式做到這一點,而適用於所有應用程式的一個標準的出現很可能讓所有的開發人員從中受益。但其中的挑戰就是彌合Java標準版和企業版之間的差別,形成一個標準的API,從而能夠用於運行在託管容器裡的公司專屬應用程式程式,也能用於希望管理自己的、無容器的標準應用程式。現在我們有了JSR-220——Enterprise Java Beans 3.0規範。隨著JSR-220的發展,它分成兩個部分:EJB3.0 persistence和EJB 3.0 core(以及其他)。
EJB3.0 persistence與先前的EJB persistence不同,它在Java 5.0裡加入了Annotations(批註)以及各種POJO persistence開發人員的經驗。
在編寫EJB3.0 Persistence的時候,它的規範還在“最後的草案”階段,有些內容還有可能發生改變。儘管如此,現在就是你研究一下規範裡很多實現的好機會;參考實現可以在Glassfish裡找到,而另外一個是實現Hibernate的Annotation和EntityManager項目。
現在讓我們從基本的東西開始:如何讓一個類在Java SE裡面保持連續性。下面就是一個簡單的例子:
public class Address {
private String street;
private String postcode;
public Address() {}
public String getStreet() { return street; }
public void setStreet(String street) { this.street = street; }
public String getPostcode() { return postcode; }
public void setPostcode(String postcode) { this.postcode = postcode; }
}
為了把類放進一個能夠被持久保持的實體,我們在一開始就加入了@Entity批註,從而讓其能夠保持持久,就像下面這樣:
import javax.persistence.Entity;
@Entity
public class Address {
…
現在,如果你得第一反應是“嗨,什麼是@Something”,那麼就讓我簡單介紹一下批註。從曆史上講,Java一直缺少在代碼裡嵌入中繼資料的方式。Javadoc是一種來源資料,用於產生文檔,使用方法是在註解區塊裡使用首碼為@的標記。這一概念建立在Xdoclet基礎之上,人們用它來承載自己的中繼資料。另外一種替代方式是用於類的匹配XML檔案,例如Hibernate除了使用類以外,還利用一個.hbm.xml檔案為同名的類承載自己的映射資訊。這兩種技術都很好用,但是對於Java 5來說,人們更希望在運行時實現看到一種更能夠驗證和發現的內聯和編譯器;這就是Annotations出現的原因。在本文裡,你需要知道批註是什麼,如何添加中繼資料,如何持久地映射一個類。
@Entity批註的作用是標記用來保持的類。為了便於更容易檢索,POJO會給每一個需求配備一個主鍵。這樣做的一種常見方法是引入一個長欄位來作為這個鍵。所以我們會把這個加到類上面:
private Long id;
@Id
@GeneratedValue
public Long getId() { return id; }
public void setId(Long id) { this.id=id; }
@Id批註表示主鍵欄位的獲得者是誰,而@GeneratedValue批註會要求persistence層為這個欄位產生一個值。這就是我們需要做的所有事情;我們現在就可以開始使用Address(地址)了。
Address address=new Address();
address.setPostcode("ZZ9 99Z");
address.setName("John Doe");
如果要保持Address,我們就需要為處理保持資料所需的每個工作單元取得一個EntityManager。Java EE和Java SE下的persistence在這一點上有很大的不同。在Java EE裡,會有很多批註讓周圍的架構來管理實體。在Java SE裡,這一任務就交給了開發人員,由他們來獲得EntityManager。我們從EntityManagerFactory取得了一個EntityManager。
EntityManagerFactory emf=null;
…
EntityManager em=emf.getEntityManager();
我們以後再回頭講是從哪裡獲得EntityManagerFactory的;現在,我們就假設它已經被初始化,我們能夠從其中獲得EntityManager。當你保持Java SE的時候,你還有責任管理資料庫的事務;你必須開始和結束資料庫的事務,所以就讓我們從獲得一個事務開始吧:
EntityTransaction tx=em.getTransaction();
tx.begin();
現在我們可以要EntityManager保持我們的Address。
em.persist(address);
然後執行事務,關閉EntityManager;
tx.commit();
em.close();
完成之後,會有一個id被分配給我們的Person,它將被寫入到資料庫裡。獲得和執行事務的這種方式對於任何用來修改對象保持狀態的代碼來說都是相當常見的。為了保證可靠性,如果出現像下面這樣的問題,它應該提示出現異常,並進行復原。
EntityManager em=emf.getEntityManager();
EntityTransaction tx=em.getTransaction();
try {
tx.begin();
// Do saves or modifications here
tx.commit();
} catch (Exception e) {
if(tx.isActive()) tx.rollback();
System.err.println("Error:"+e);
} finally {
em.close();
}
假設這段代碼是放在下面用來修改資料庫的例子的周圍。如果要檢索資料,我們只需要獲得EntityManager就行了。
要檢索先前儲存的Address,我們可以把id用作參考;我們不需要來自EntityManager的事務,所以這個過程就變得很簡單了:
Address address2=em.find(Address.class,address.getId());
如果我們想要通過郵遞區號找到一個Address,我們可以使用EJB查詢語言——EJBQL來定義查詢,用EntityManager來建立這一查詢。
Query q=em.createQuery("select address from Address as address where postcode=:param");
這個查詢會著手尋找郵遞區號符合要求的地址(Address被保持,返回的結果被作為Address對象),也就是符合“param”參數為“to be set”的地址。現在我們可以設定這個參數:
q.setParameter("param",name);
要獲得結果,就要對查詢調用getResultList,如果我們希望得到0個或者更多的結果,或者我們只希望獲得1個結果的話。
List<Address> l=(List<Address>)q.getResultList();
or
Address addresstochange=(Address)q.getSingleResult();
我們最後要做的事情是更改Address(地址),並把它的改變合并到資料庫裡;假設我們已經通過先前的查詢檢索到了一個Address。
addresstochange.setStreet("A Different Street");
…
em.merge(addresstochange);
…