本文對隨 IBM? Rational? Application Developer V6 一起提供的數據訪問服務(Data Access Services,DAS)進行了概述,并對這些訪問服務在使用服務數據對象(Service Data Object,SDO)的面向服務的體系結構 (SOA) 中扮演的角色進行了說明。
引言
IBM Rational Application Developer for WebSphere? Software V6 所包含 JDBC Data Access Services 提供了對面向服務的體系結構的持久化層的標準化訪問。數據訪問服務 (DAS) 與服務數據對象 (SDO) 密切相關,因此要了解 DAS 的概念,首先需要了解一下 SDO。
在本文講述的高級部分,將給出一個端到端的示例應用程序,該應用程序使用適合開發人員和架構師使用的 JDBC DAS。該示例使用 XML 對象關系映射信息保存對 SDO 對象圖的更改。(請參閱參考資料,以獲得有關 SDO 的更多信息。)
什么是 SDO?
服務數據對象(Service Data Objects,SDO)是一項新興標準,用于表示企業應用程序中的數據。SDO 是信息的容器,設計用于提升開放標準和互操作性。SDO 提供了在整個企業應用程序中表示信息的方法,包括表示層、業務邏輯層和此類層之間的通信,如圖 1 所示。
圖 1. SDO 概述
服務數據對象的主要特性包括:
-
SDO 可以包含嵌套對象。此功能稱為對象圖,是一種非常靈活的表示數據的方式。例如,圖 2 中的 SDO 就表示一個有各種產品的多個訂單的客戶:
圖 2. SDO 數據圖
-
SDO 支持 XPath,可以訪問其封裝的數據。XML 路徑語言 (XPath) 是一項開放標準,是由 World Wide Web Consortium (W3C) 制定的,用于從 XML 文檔訪問數據。例如,可以使用以下字符串訪問特定的產品:CustomerOrder/Product[name='MP3Player']
,其中,CustomerOrder 為 Customer 和 Order 之間定義的關系。
-
SDO 可以作為 XML 構件或 Java? 對象存在。借助對 XML 的這項透明支持,直接使用 <datagraph> 標記作為開頭來傳遞 XML SDO,就可以通過 Web 服務(或任何 XML 傳輸,如 REST 或 XML-RPC)傳遞 SDO。而且,僅在 SDO v1 中使用更改摘要時,才有必要使用 <datagraph> 標記。在其他所有情況下,可以使用任何標記。
-
SDO 包含更改摘要。SDO 更改摘要作為所有活動的歷史記錄使用,通過使用此功能,應用程序可以將舊數據和新數據區分開。例如,加入某個客戶決定下新訂單。接受訂單的企業系統由圖 3 中的高級組件組成。請注意,包含新訂單的 SDO 將從門戶服務器傳遞到后端服務。如果沒有更改摘要,后端服務必須將 SDO 中的所有數據放入數據庫。不過,由于可以訪問 SDO 更改摘要,因此,只需要將新數據放入數據庫即可,從而提高后端服務的效率。此外,門戶服務器可以通過使用更改摘要來傳遞更小的 SDO,該 SDO 中僅包含在前端所做的更改。
圖 3. 更改摘要
-
SDO 是開放標準。SDO 1.0 和 2.0 規范均是由 BEA? 和 IBM 聯合發布的(請參閱參考資料)。任何組織都可以免費使用和實現這些標準。
什么是 DAS?
數據訪問服務 (Data Access Service) 根據 SDO 1.0 標準保存 SDO。DAS 可以采用任何持久化機制實現。例如,Rational Application Developer V6 包括了一個 JDBC DAS 和一個 EJB 實體 Bean DAS,允許采用標準方式將 SDO 保存到各種后端系統,從而提升企業應用程序內的互操作性和標準。
圖 4. DAS 概述
DAS 是一項新興的規范,其標準化進程仍在進行之中?,F在稱為 DAS 的新一輪工作就是即將推出的數據訪問服務 (DAS) 標準??梢詫?DAS 稱為 DAS 2.0。DAS 將對 SDO 2.0 規范形成補充,正在制定之中(DAS 被認為處于 SDO 2.0 規范之外)。
面向服務的體系結構中的數據訪問服務
SDO 數據訪問服務非常適合作為 SOA 服務公開。他們提供了一個標準,用于構建可以在 SOA 服務間共享的后端服務。例如,假如有一個必須和兩個不同業務進行通信的企業系統。這兩個業務服務使用完全不同的技術保存信息。如果傳遞給這些服務的消息為 SDO,則兩個服務都可以使用 DAS,企業應用程序可以將其看作同一個組織而進行處理,如圖 5 中所示。
圖 5. SOA 中的 SDO 數據訪問服務
DAS 還可以提高 SOA 的可維護性。實現 SOA 的一個常見毛病就是會假設公開服務總是有好處的。當公開了服務時,要更改非常困難——對于那些向客戶或公眾公開某種功能的服務更是如此。例如,假設某家銀行有一項已公開了數年的服務,由于政府法規的原因,現在必須對其進行更改——在網上傳輸的消息必須經過加密,如圖 6 中所示。
圖 6. SOA 中的 DAS 和可維護性
如果有數百合作伙伴訪問該服務,該銀行不會輕易更改服務,因為其合作伙伴將不再能與他們開展業務。該銀行的最佳選擇可能就是構建另一個 99% 冗余的服務,并盡力說服其合作伙伴轉而使用新服務。這將使用大量資源,而所得到的業務價值也有限。
將 SDO 和 DAS 配合使用,可以減緩這類問題,因為 SDO 是動態性非常強的消息。如果該銀行使用的是 SDO,則可以直接通知其合作伙伴對添加的信息進行加密,而不會更改已公開的服務——只需要更改傳遞給該服務的消息。如果某個合作伙伴仍然發送舊 SDO XML 格式的消息,通過檢查 SDO 的內容(并可能與不兼容的業務合作伙伴聯系),銀行的應用程序將能夠對此類情況作出判斷,然后按照以前的方式處理此類信息。
使用 SDO 數據訪問服務的業務案例
在現有持久化技術的基礎上將 SDO 和 DAS 結合使用,除了 SOA 的好處之外,其業務價值何在呢?請考慮以下管理方面的特征:
-
SDO 是一項開放標準。由于 SDO 是一項公開的標準,因此不會出現不得不選用某個供應商的情況。截至本文發布時,BEA、IBM、Versant、Versata 和 XCalia 均推出了 SDO 實現。同樣,也已計劃對 SDO 的數據訪問進行標準化。
-
SDO 和 DAS 可以減少業務所必須維護的代碼量。數據訪問服務提供了一種標準的方法,用于保存封裝在 SDO 中的信息,而不受后端系統的影響(不管此后端系統是使用 JDBC 訪問的關系數據庫、使用視圖 Bean 訪問的 LDAP 服務器或是具有 DAS 實現的其他后端系統)。實際上,為了使用異構后端系統而編寫的自定義代碼與數據訪問服務采用標準的方式進行了整合。需要維護的代碼較少,通??梢员M可能減少潛在的缺陷,從而縮短投入市場的時間和減少風險。
-
將 SDO 和 DAS 結合使用,不需要受具體的持久化技術限制。DAS 不僅使應用程序無需依賴于數據庫或操作系統,而且還使應用程序獨立于整個持久化技術。通過使用多個數據訪問服務,應用程序可以支持這些中介的基礎持久化機制,而不用更改業務邏輯或呈現邏輯。對于 IT 環境復雜的組織,這樣可以減少成本、整合資產,并可以減少將來進行高成本技術更改的風險。
-
使用 SDO 和 DAS 有得有失。這兩項均是新興技術,尚處于早期發布階段。很多數據訪問服務可能不支持其他持久化技術的最先進功能(除非 DAS 專門為支持該技術而構建)。例如,IBM 的 JDBC Data Access Service 就尚不支持 SDO 表群集環境的分布式緩存。另外,若要充分發揮 SDO 和 DAS 的潛力,可能需要對各種新技術有所了解,包括 Web 服務、XPath 及 SDO 規范。對于開發組織,可以需要進行培訓。
按部就班,使用 JDBC Data Access Service
本文剩下的部分將給出一個實例應用程序的實現。就功能而言,CloseOrderApplication 將使用 Rational Application Developer V6 包含的 JDBC DAS 關閉客戶的訂單。該應用程序將從數據庫檢索一個 SDO 對象圖,對其進行更小,然后保存更改。將數據庫架構映射到 SDO 對象圖的元數據是使用 XML 編寫的。
JDBC DAS 編程模型
圖 7 所示的關系圖演示了使用 JDBC Data Access Service 開發應用程序時應該有用的編程模型。
圖 7. JDBC DAS 編程模型
|
關于示例應用程序
此示例不僅是試驗性的代碼,因為其中實現了 JavaEE 最佳實踐和實際錯誤處理。如果確實需要利用 JDBC Data Access Service 的代碼(通常不過寥寥幾行而已),清單 1 和清單 6 無疑是最為相關的了。數據庫設置、JavaEE 數據源定義、XML 元數據的 JNDI 查詢以及異常處理均屬于 JavaEE 開發期間要做的工作,而不屬于 SDO JDBC DAS。 |
|
在此模型中,JDBC DAS 使用 ConnectionWrapper 對 JDBC Connection 加以包裝,以連接到數據存儲區。使用 MetadataFactory 創建了 Metadata 的實例。然后使用各種構造(如 Tables、Columns 及 Relationships)定義元數據。數據庫查詢的等效項在元數據中定義為篩選器。不過,在此示例中,元數據、表、列、關系和篩選器均在元數據中定義,且在 XML 映射文檔需要時透明地創建。(請參閱參考資料,以了解如何如上所示,在運行時使用元數據 API。)定義了元數據后,就會將其與 ConnectionWrapper 一起使用,以創建 JDBCAccess。中介可以獲取和保存 SDO DataObject 圖。
我們將通過執行以下任務來實現此實例應用程序:
-
創建 JaveEE 項目
-
設置數據庫
-
定義 XML 元數據
-
創建方法
-
創建 JDBC 連接包裝類
-
創建 JDBC 中介
-
從數據庫檢索 SDO DataObject 圖
-
保存 SDO 圖
-
關閉連接
-
檢查應用程序異常
-
使用 Servlet 測試應用程序
示例應用程序的先決條件
|
此示例假設為 SDO DAS 使用 JavaEE 環境。不過并不需要應用程序服務器。IBM JDBC DAS 可以用于任何支持 Java SE 1.3 或更高版本的應用程序中。 |
|
1. 創建 JavaEE 項目
在 Rational Application Developer 的 J2EE Perspective 中:
-
選擇 File => New => Enterprise Application Project。將其命名為 CloseOrder
,然后選擇 Finish。
-
右鍵單擊 CloseOrder,選擇 New => Dynamic Web Project,將其命名為 CloseOrderWeb
,然后單擊 Finish。
2. 設置數據庫
圖 8 顯示了示例應用程序的數據庫架構。其中包含一個 customer 條目和一個指向 order 條目的外鍵:
圖 8. 數據庫架構
|
請注意,此處假設管理用戶名和密碼均為 db2admin 。
|
|
-
啟動 DB2 命令行處理程序。缺省情況下,可以采用以下方式啟動此工具:
-
Linux? 或 UNIX?:
- 作為數據庫管理員登錄(比如
su db2admin
)
- 鍵入
db2
并按 Enter。
-
Windows?:
- 選擇 Start => All Programs => IBM DB2 => Command Line Tools => Command Line Processor。
-
使用命令行處理程序執行以下代碼:
清單 1. DB2 命令
db2 => CREATE DATABASE EXAMPLE
db2 => CONNECT TO EXAMPLE USER db2admin USING db2admin
db2 => CREATE TABLE CUSTOMER(CUST_ID INTEGER NOT NULL, NAME VARCHAR(250), ORDER_ID INTEGER)
db2 => ALTER TABLE CUSTOMER PRIMARY KEY(CUST_ID)
db2 => CREATE TABLE ORDER(ORDER_ID INTEGER NOT NULL, STATUS VARCHAR(250), TOTAL INTEGER, CUSTOMER_ID INTEGER)
db2 => ALTER TABLE ORDER PRIMARY KEY(ORDER_ID)
db2 => INSERT INTO CUSTOMER(NAME, CUST_ID, ORDER_ID) VALUES ('Roland Barcia', 1, 2)
db2 => INSERT INTO CUSTOMER(NAME, CUST_ID, ORDER_ID) VALUES ('Geoffrey Hambrick', 2, 1)
db2 => INSERT INTO ORDER(ORDER_ID, STATUS, TOTAL, CUSTOMER_ID) VALUES (1, 'OPEN', 88, 1)
db2 => INSERT INTO ORDER(ORDER_ID, STATUS, TOTAL, CUSTOMER_ID) VALUES (2, 'OPEN', 188, 5)
db2 => ALTER TABLE CUSTOMER FOREIGN KEY(ORDER_ID) REFERENCES ORDER(ORDER_ID)
|
-
CloseOrder 示例應用程序對 JDBC 數據庫使用 JNDI 上下文引用,以避免硬編碼數據庫連接信息。展開 CloseOrderWeb
,并雙擊 Deployment Descriptor: CloseOrderWeb。
-
選擇 Reference 選項卡,選擇 Add... => Resourse reference,然后輸入或選擇字段值,如圖 9 中所示。
圖 9. 數據源 JNDI 上下文引用
-
為 JNDI name 字段輸入 jdbc/db2/Example
,如圖 10 中所示。
圖 10. 數據庫 JNDI 名稱
3. 定義 XML 元數據
若要將數據架構映射到 SDO 數據圖,則必須定義中介元數據。
圖 11. O/R 映射
可以在運行時使用 com.ibm.websphere.sdo.mediator.jdbc.metadata.Metadata 定義元數據,圖 7 對此作了簡單描述(請參閱參考資料,以獲得關于在運行時定義元數據的文檔)。不過,我們的示例在 XML 中定義元數據。示例應用程序將元數據 XML 文件添加到類路徑中,從而簡化打開指向該文件的 java.io.InputStream 的過程,如要求創建中介時。
-
在 Rational Application Developer 中,右鍵單擊 CloseOrderWeb 項目,然后選擇 New => Source Folder。
-
輸入 xml
作為文件夾名稱,然后選擇 Finish。
-
右鍵單擊 CloseOrderWeb,然后選擇 Java Resources => metadata,再選擇 New => other... => Simple => Folder => Next。
-
將文件夾命名為 DAS
并選擇 Finish。
-
右鍵單擊 DAS 文件夾,然后采用類似的方式創建一個名為 metadata.xml
的新文件。
-
插入以下語句作為其內容:
清單 2. 將元數據添加到 XML
<?xml version="1.0" encoding="ASCII" ?>
<Metadata rootTable="CUSTOMER" xmlns:="http:///com/ibm/websphere/wdo/mediator/rdb/metadata.ecore" >
<tables name="CUSTOMER">
<columns name="CUST_ID" type="int" />
<columns name="NAME" type="string" />
<columns name="ORDER_ID" type="int" />
<primaryKey columns="CUST_ID" />
<foreignKeys columns="ORDER_ID" />
<queryInfo filter="( CUST_ID = ? )">
<filterArguments name="CUST_ID" type="int" />
</queryInfo>
</tables>
<orderBys column="CUSTOMER.NAME" />
<tables name="ORDER">
<columns name="ORDER_ID" type="int" />
<columns name="STATUS" type="string" />
<columns name="TOTAL" type="int" />
<primaryKey columns="ORDER_ID" />
</tables>
<relationships name="OWNER" oppositeName="ORDER_RELATION" childKey="CUSTOMER"
parentKey="ORDER" exclusive="false" />
</Metadata>
|
列和主鍵的 O/R 映射應當較為直觀。請考慮以下對某些其他元數據標記的描述:
-
<tables rootTable="CUSTOMER">
SDO 數據對象圖必須定義訪問的根入口點。在此應用程序中 customer 就是根對象。
-
<queryInfo>
此標記定義篩選器。如果未定義篩選器,元數據將仍然有效;此時中介會將所有的客戶(以及所有相關訂單)作為 SDO 數據對象圖返回。此處定義的篩選器將 SDO 圖的返回縮小,使其僅包含與 filterArgument 匹配的客戶。當中介從數據庫檢索此 SDO 圖時,將要求傳入一個名為 CUST_ID 的 int 類型參數。請注意,該參數并沒有設置 name = "CUST_ID"
,因為其可能與數據庫列名稱不同。
-
<relationships>
此標記定義 CUSTOMER.OPEN_ORDER_ID 的外鍵關系。在此關系中,customer 是子項,而 order 為父項。"Exclusive" 設置為 false,以指示中介檢索所有相關訂單,甚至包括沒有 customer 引用的 order。如果將其設置為 true,則僅檢索至少有一個子 customer 引用的 order 項。
(如果收到驗證錯誤“Element or attribute do not match QName
”,可以將其忽略。本文是入門級的文章,將不在 Rational Application Developer 內設置驗證。)
-
示例應用程序使用 JNDI 上下文引用查詢元數據文件的位置。這樣,應用程序就可以避免對文件名稱進行硬編碼了。展開 CloseOrderWeb,然后雙擊 Deployment Descriptor: CloseOrderWeb。
-
選擇 Reference 選項卡,然后選擇 Add... => Resourse reference,并按照圖 12 所示填寫值。
圖 12. 元數據資源環境引用
-
在 JNDI name 字段中輸入 cell/persistent/string/CloseOrderMetadata
,如圖 13 所示。
圖 13. 元數據 JNDI 名稱
4. 創建方法
現在已經準備好,可以開始開發應用程序的代碼了。
-
右鍵單擊 CloseOrderWeb 項目,并選擇 New => Class。
-
在 package 中輸入 developerworks.sdo.example
并將其命名為 CloseOrderApplication
。
為了更好地描述該應用程序,將在接下來的每一步對 CloseOrderApplication 類的各個方法單獨進行討論。首先是該類的唯一公共方法 closeOrder(),該方法負責整個示例應用程序的組織(圖 14)。
圖 14. CloseOrder 示例應用程序的事件序列
以下方法是應用程序的入口點,圖 14 顯示的每個步驟幾乎都由其進行組織:
清單 3. closeOrder 方法
public void closeOrder(int customerId) {
ConnectionWrapper conn =
getConnectionWorker("java:comp/env/jdbc/DASDefault "); [1]
JDBCAccess mediator =
createAccessWorker("java:comp/env/DAS/XMLMetadata ", conn); [2]
DataObject order = null;
try {
order = getOpenOrderWorker(customerId, mediator); [3]
} catch (NoCustomer nc) {
Logger.warn("CloseOrder app could not find specified customer. [4]
Prompting end user to create one or cancel transaction.", nc);
// ... code to notify presentation layer would go here ...
} catch (OrderNotOpen ono) {
Logger.warn("CloseOrder app could not find order associated with
given customer. Notifying end user.", ono); [5]
// ... same as above ...
}
order.set("STATUS", "CLOSED"); [6]
persistChangesWorker(order, mediator); [7]
closeConnectionWorker(conn); [8]
}
|
此方法的主要任務是:
-
獲取 JDBC 連接包裝類。
getConnectionWorker() 代碼詳細說明數據庫如何連接。輔助方法需要 JDBC 的 JNDI 上下文引用。
-
創建訪問。
輔助方法需要 ConnectionWrapper 和對 metadata.xml 的 JNDI 上下文引用。
-
獲取客戶的開放訂單。
輔助方法使用中介獲取 SDO 對象圖,遍歷到與根 customer 項相關的 order,然后將其返回。
-
處理無客戶的異常情況。
獲取開放訂單的輔助方法可能引發 NoCustomer 異常。除了記錄此情況并通知表示層之外(使用 closeOrder() 進行),典型的異常處理還可能包括使用新連接重試,或嘗試采用名稱替代 ID 進行查找。
-
處理無開放訂單的異常情況。
獲取開放訂單的輔助方法可能引發 OrderNotOpen 異常。對此的恰當異常處理由讀者自行完成。
-
關閉訂單。
修改 order SDO DataObject 的狀態字符串。
-
保存訂單。
將 order SDO DataObject 保存到數據庫。
-
關閉連接。
關閉連接。
5. 創建 JDBC 連接包裝類
以下代碼示例包含創建數據庫連接的輔助方法。此方法完成了圖 14 所示序列的步驟 (A) 和 (B) 的工作。
清單 4. getConnectionWorker 方法
private ConnectionWrapper getConnectionWorker(String ctxRef) {
Connection conn = null;
try {
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup(ctxRef);
conn = ds.getConnection();
conn.setAutoCommit(false);
conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
return ConnectionWrapperFactoryImpl.soleInstance.createConnectionWrapper(conn);
} catch (NamingException ne) {
throw new CloseOrderRuntime("CloseOrder could not lookup jdbc string
binding: "+ctxRef, ne);
} catch (SQLException sqle) {
throw new
CloseOrderRuntime("CloseOrder failed to make database connection", sqle);
}
}
|
此方法的內容對于具有 JDBC 經驗的 JavaEE 開發人員非常簡單。唯一特定于 JDBC DAS 代碼是從 ConnectionWrapperFactory 創建 ConnectionWrapper。請注意,此處使用了一個泛型運行時異常重新引發假定將由 JavaEE 應用程序中更高層處理的異常。
6. 創建 JDBC 中介
以下代碼示例包含創建中介的輔助方法。此方法完成了圖 14 所示序列的步驟 (C) 和 (D) 的工作。
清單 5. createAccessWorker 方法
private JDBCAccess createAccessWorker(String ctxRef, ConnectionWrapper conn) {
JDBCAccess mediator = null;
String xmlPath = null;
try {
InitialContext ctx = new InitialContext();
xmlPath = (String) ctx.lookup(ctxRef); <b>[1]</b>
InputStream is = getClass().getClassLoader().getResourceAsStream(xmlPath); <b>[2]</b>
mediator = JDBCAccessFactory.soleInstance.createAccess(is, conn); <b>[3]</b>
} catch (NamingException ne) { <b>[4]</b>
throw new CloseOrderRuntime("CloseOrder could not lookup metadata string
binding: "+ctxRef, ne);
} catch (FileNotFoundException fnfe) {
throw new CloseOrderRuntime("CloseOrder app cannot find: "+xmlPath, fnfe);
} catch (IOException ioe) {
throw new CloseOrderRuntime("CloseOrder app has filesystem error", ioe);
} catch (AccessException me) {
throw new CloseOrderRuntime("Metadata inside "+xmlPath+" is invalid.", me);
}
return mediator;
}
|
此方法的主要任務是:
-
使用 JNDI 上下文引用獲取文件名。
采用與查詢 JDBC 數據源類似的方法檢索 XML 元數據文件名。
-
創建文件流
使用文件名創建指向 XML 元數據文件的常規 java.io.InputStream。
-
創建 JDBC 訪問。
使用 JDBCAccessFactory,并將文件流和數據庫連接包裝類作為參數,以創建中介。
-
處理異常。
此處也是使用一個泛型運行時異常處理各種異常。
7. 從數據庫檢索 SDO DataObject 圖
以下代碼片段包含了從數據庫檢索 SDO 對象圖并返回客戶的開放訂單的輔助方法。此方法完成圖 14 所示序列中的步驟 (E) 的工作。
清單 6. getOpenOrderWorker 方法
private DataObject getOpenOrderWorker(int customerId, JDBCAccess mediator) throws NoCustomer, OrderNotOpen {
DataObject graph = null;
try {
DataObject param = mediator.getParameterDataObject();
param.setInt("CUST_ID", customerId); [1]
graph = mediator.getGraph(param); [2]
}
catch(AccessException me) {
throw new CloseOrderRuntime("CloseOrder app failed to get customer graph from
mediator. CUST_ID="+customerId, me);
}
List cList = graph.getList("CUSTOMER"); [3]
if(cList.size() == 0) {
throw new NoCustomer("CloseOrder app could not find customer for
CUST_ID="+customerId);
}
DataObject customer = graph.getDataObject("CUSTOMER.0"); [4]
if(customer.getInt("ORDER_ID") == 0 || graph.getList("ORDER").size() != 1) {
throw new OrderNotOpen("CloseOrder app did not find an open [5]
order for customer with CUST_ID="+customerId);
}
return customer.getDataObject("ORDER_RELATION"); [6]
}
|
此方法的主要任務是:
-
創建參數。
創建一個名為 CUST_ID 的參數,并將其設置為 customerId
。此參數在篩選器中使用,以將 SDO 圖限制為僅包含具有元數據 XML 中指定的特定 ID 的客戶。
-
獲取 SDO DataObject 圖。
使用步驟 1 中構造的參數對中介調用 getGraph 方法。此圖中應包含客戶及其相關訂單。
-
檢查客戶是否存在。
getList("CUSTOMER") 方法返回 SDO 圖中所有客戶數據對象的列表。如果大小為零,則將引發 NoCustomer 應用程序異常。
-
獲取客戶。
從 SDO 圖獲取客戶。請注意,追加到 CUSTOMER.0
的零是必需的,用以指示要檢索 customer 列表的哪個元素(在此例中,列表中僅有一個客戶)。
-
檢查是否存在開放訂單。
如果訂單不是開放狀態,則不能對其進行關閉操作。將檢查 OPEN_ORDER_ID 外鍵,還將檢查 order DataObject 列表是否為非零。
-
返回開放訂單。
通過遍歷元數據中定義的關系,從 customer 子圖檢索開放訂單。
8. 保存 SDO 圖
以下代碼示例包含保存已更新 SDO DataObject 圖的輔助方法。此方法完成了圖 14 所示序列的步驟 (G) 的工作。
清單 7. persistChangeWorker method
private void persistChangesWorker(DataObject graph, JDBCAccess mediator) {
try {
mediator.applyChanges(graph);
} catch(AccessException me) {
throw new CloseOrderRuntime("CloseOrder app failed to persist SDO graph.
Access="+mediator+"\nGraph="+graph, me);
}
}
|
9. 關閉連接
以下代碼示例包含關閉數據庫連接的輔助方法。此代碼完成了圖 14 所示序列的步驟 (H) 的工作。
清單 8. closeConnectionWorker 方法
private static void closeConnectionWorker(ConnectionWrapper conn) {
try {
conn.getConnection().close();
} catch (SQLException sqle) {
throw new CloseOrderRuntime("CloseOrder app failed to close
ConnectionWrapper="+conn, sqle);
}
}
|
10. 檢查應用程序異常
CloseOrderApplication 使用了以下異常,這些異常都位于 developerworks.sdo.example.exception 包內:
清單 9. CloseOrderApplication 所使用的異常
public class CloseOrderRuntime extends RuntimeException {
public CloseOrderRuntime() {
super();
}
public CloseOrderRuntime(String msg) {
super(msg);
}
public CloseOrderRuntime(Exception nested) {
super(nested);
}
public CloseOrderRuntime(String msg, Exception nested) {
super(msg, nested);
}
}
public class NoCustomer extends Exception {
public NoCustomer() {
super();
}
public NoCustomer(String msg) {
super(msg);
}
}
public class OrderNotOpen extends Exception {
public OrderNotOpen() {
super();
}
public OrderNotOpen(String msg) {
super(msg);
}
}
|
11. 使用 Servlet 測試應用程序
-
右鍵單擊 Deployment Descriptor: CloseOrderWeb 項目,然后選擇 New => Servlet...。
-
在 Name 字段輸入 TestCloseOrder
,然后單擊 Next。
-
在 Java package 中輸入 developerworks.sdo.example.test
,然后單擊 Finish。
-
插入以下代碼作為 doGet
方法的內容:
清單 10. 測試 Servlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
String customerId = request.getParameter("customerId");
CloseOrderApplication coa = new CloseOrderApplication();
coa.closeOrder(Integer.parseInt(customerId));
response.getWriter().print("Close order request processed successfully.");
}
|
-
選擇 Servers 選項卡,右鍵單擊 WebSphere Application Server v6.0,然后選擇 Start。
-
再次右鍵單擊服務器,并選擇 Add and remove projects...,以將 CloseOrder EAR 項目部署到服務器。
-
部署了項目之后,使用以下 URL 在 Web 瀏覽器中打開管理控制臺:http://localhost:9060/admin。
-
選擇 Log in => Security => Global security => JAAS Configuration => J2C Authentication data => New,并按照圖 15 所示填寫表單。
圖 15. 數據庫身份驗證入口
-
選擇 OK,然后選擇 Save。
-
選擇 Environment => WebSphere Variables => DB2UNIVERSAL_JDBC_DRIVER_PATH 并輸入您的 DB2 驅動程序目錄。Windows 下的缺省值為 C:\Program Files\IBM\SQLLIB\java
。
-
選擇 Resources => JDBC Providers => New 并按照圖 16 所示填寫表單。
圖 16. JDBC Provider 配置
-
依次單擊 Next、OK 和 Save。
-
選擇 DB2 Universal JDBC Driver Provider (XA) => Data sources => New。
-
插入 jdbc/db2/Example
作為 JNDI name。
-
選擇 DB2 Login 作為 Component-managed authentication alias。
-
輸入 EXAMPLE
作為 Database name。
-
輸入 localhost
(或 DB2 的主機)作為 Server name,然后單擊 Save。
-
為了確保數據源正常工作,請選擇 DB2 Universal JDBC Driver XA DataSource 旁邊的框,并單擊 Test connection。
-
最后一個管理步驟就是 metadata.xml 文件的 JNDI 字符串綁定。選擇 Environment => Naming => Name Space Bindings => New => String => Next 并按照圖 17 所示填寫表單。Name Space value 中的 Name 為 string/CloseOrderApp/metadata
。
圖 17. XML 文件名字符串綁定
-
選擇 Next => Finish 和 Save。
-
重新啟動服務器,以確保所有 JNDI 綁定均已更新。
-
若要運行該應用程序,請將以下 URL 輸入到 Web 瀏覽器中:http://localhost:9080/CloseOrderWeb/TestCloseOrder?customerId=2
|
|
結束語
JDBC Data Access Service 提供了對面向服務的體系結構的持久化層的標準化訪問。本文演示了 SDO DAS 如何如何適應大型的企業部署,以及如何使用簡潔且用戶友好的 XML 元數據將現有數據庫架構映射到 SDO。