JDO(Java Data Object)是JCP中較早開發出來並形成規范的JSR12,該規范對數據的持久化存儲進行了一系列規范,並已有眾多的商業產品和開源項目是基於該規范。作為一種需要引起重視的技術,研究並探討其企業應用可行性是十分重要的。
前言
在企業級的應用開發中,常需要有良好的持久化技術來支持數據存儲。通過良好的規范或API,將企業的領域業務對象進行持久化存儲,大多采用O/R映射技術來進行模式化的數據轉換及自動映射工作。
JDO(Java Data Object)是JCP中較早開發出來並形成規范的JSR12,該規范對數據的持久化存儲進行了一系列規范,並已有眾多的商業產品和開源項目是基於該規范。作為一種需要引起重視的技術,研究並探討其企業應用可行性是十分重要的。
以下主要對JDO(JDO 1.0規范)的應用開發技術作扼要介紹,通過該文,可以由淺入深、並較為全面地了解JDO,掌握主要的技術細節及過程,理解其運行機制,並對企業級應用有個總體的把握,這將有助於企業應用軟件的技術選型、體系架構及分析設計活動。
該文適合企業應用架構師、及關心數據持久層設計開發人員。
JDO基本思想及特點
企業信息系統的一個重要問題是解決數據的存儲,即持久化。在軟件開發過程中,分析員分析領域業務,提取出領域業務模型,並對應設計出數據庫中需要進行存儲業務數據的數據庫表及相應字段。
並根據業務流程,設計業務處理邏輯單元,進行數據的加工、處理及存儲、查詢等業務。其中一個較為繁煩、枯燥的工作,就是處理大量的數據持久化代碼。為了解決數據從業務對象層向數據存儲層之間的轉換工作,JDO提供了相應的開發規范及API,解決了由Java對象直接存儲為數據庫相應表的底層處理過程,有助於設計人員更加專注於面向業務流程、面向業務對象等較高層次的應用。
由於采用JDO的映射機制,能降低了業務系統與數據存儲系統的耦合,使得業務系統相對於關系數據庫或對象型數據庫,具有可移植性,同時,由於采用面向對象(而非傳統的面向記錄)的持久化技術,系統更為輕便、簡潔,增強了可維護性。
JDO應用示例及分析
以下將通過一些示例,由淺及深地講解JDO技術。
臨時對象與持久對象
這是一個普通的業務對象的代碼。
package business.model;
public class Book {
private String isbn;
private String name;
private Date publishDate;
public void setISBN(String isbn){
this.isbn = isbn;
}
public String getISBN(){
return this.isbn;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setPublishDate(Date pubDate){
this.publishDate = pubDate;
}
public Date getPublishDate(){
return this.publishDate;
}
}
現在將它作為一個JDO中對象保存到數據庫中。代碼如下:
Book book = new Book();
book.setISBN(“isbn-1234567”);
book.setName(“Java設計模式”);
PersistenceManager manager = persistenceManagerFactory.getPersistenceManager();
manager.currentTransaction().begin();
manager.makePersistence(book);
manager.currentTransaction().commit();
Book類的實例book對JDO的API而言,就是一個持久對象。類Book是可持久類。那任何一個普通Java類都是JDO的可持久類嗎?不是的。只有具備以下的條件,一個對象才可以被JDO持久到數據庫中。
它所屬類應標記為可持久的類,有以下兩種方法:
顯式:實現接口,Javax.jdo.PersistenceCapable即可;
隱式:以Sun的JDO參考實現為例,Book.Java類的相同路徑下還須有Book.jdo文件。
並通過字節碼增強工具(本例采用Sun的字節碼增強工具)處理,
javac Book.Java
Java com.sun.jdori.enhancer.Main Book.class Book.jdo。
通過上述兩種方法,獲得的Book.class才是一個可持久的類。
字節碼增強的有如下功能:當應用程序通過set方法修改某個字段1時,由於通過增強過程,在其內部插入了某些代碼,JDO會獲得數據狀態變化的信息,從而在持久過程中,進行有選擇性的處理。
按照JDO規范,增強後的類可以在不同的JDO實現上使用,而無需重新編譯或增強。
並不是所有Book對象都是持久對象,只有當makePersistence後,該對象才是持久對象,並會通過JDO實現存儲到數據庫中。通過JDO的供應商擴展標記符(vendor-extension),可詳細描述Book類的存儲特性,如為該可持久類指定數據庫表和對應字段。
持久對象查詢
JDO查詢主要有以下兩種方式。
使用Extend查詢
Extend可以查詢指定類及子類的持久對象。
PersistenceManager manager = persistenceManagerFactory.getPersistenceManager();
manager.currentTransaction().begin();
Extend extend = manager.getExtend(Book.class,true);//true表明同時查詢子類
Iterator it = extend.iterator();
while(it.hasNext()){
Book book = (Book)it.next();
System.out.println(book.getISBN());
}
extend.closeAll();
manager.currentTransaction().commit();
Extend查詢方法,提供了一種基於類的查詢途徑,它可以與下面的Query構成更為強大的查詢。
使用Query查詢
Query可以指定過濾條件,是一種常用的查詢方式。
下例是查找條件為“書名以‘Java設計模式’開頭且出版日期小於今天”的書籍。
String filter = “((String)name).startsWith(”Java設計模式”) && publishDate < today”;
Query query = pm.getQuery(Book.class,filter);
query.declareImports(“import Java.util.Date”);
query.declareParameters(“Date today);
Date today = new Date();
results = (Collection)query.execute(today);//傳入參數值today
if (results.isEmpty()){
System.out.println(“No data!”);
}else{
Iterator it = results.iterator();
while(it.hasNext()){
Book book = (Book)it.next();
System.out.println(“Book Name:” + book.getName() + “, ISBN:” + book.getISBN());
}
}
注:該條件使用了一個變元‘today’,通過“declareParameters”來聲明該變量,並在“execute”方法中傳入該變量的實例。
這種帶參數的查詢,很類似於我們以前采用JDBC的帶?的查詢方式。
其中startsWith(String s)是JDO提供的標准字符方法,類似的方法還有endsWith(String s)。
JDOQL:上述使用的就是一個JDOQL樣例,JDOQL是JDO規范一個組成部分。使用JDOQL可以使用應用在不同的JDO實現上運行。為了解決JDOQL的某些不足,JDO規范提供了支持特定JDO供應商查詢語句接口。
查詢排序
下例是將查詢結果按“出版日期降序、書名升序”進行排序。
Query query = pm.newQuery(Book.class, filter);
String orderStr = “publishDate decending, name ascending”;
query.setOrdering(orderStr);
results = query.execute(today);
對象更新
當客戶端對業務數據進行了更新後,需要通過業務過程將其更新到持久層中。
這有兩個過程,首先根據主鍵找到該實例,接著更新字段及提交。
如下例,將指定書目編號的書本的出版日期進行更改。
public void updateBookPublishDate(String isbn, Date newDate){
PersistenceManager pm = null;
try{
pm = pmf.getPersistenceManager();
Object obj = pm.newObjectIdInstance(Book.class,isbn);
Book book = (Book)pm.getObjectById(obj,true);
book.setPublishDate(newDate);
}catch(Exception e){
xxxContext.setRollbackOnly();
throw new Exception(e);
}finally{
try{
if (pm != null && !pm.isClosed()){
pm.close();
}
}catch(Exception ex){
System.out.println(ex);
}
}
注,在PersistenceManager使用newObjectIdInstance()方法時,JDO是如何知道通過書目編號ISBN來找到該對象呢?