本文對隨 IBM? Rational? Application Developer V6 一起提供的數(shù)據(jù)訪問服務(wù)(Data Access Services,DAS)進行了概述,并對這些訪問服務(wù)在使用服務(wù)數(shù)據(jù)對象(Service Data Object,SDO)的面向服務(wù)的體系結(jié)構(gòu) (SOA) 中扮演的角色進行了說明。
引言
IBM Rational Application Developer for WebSphere? Software V6 所包含 JDBC Data Access Services 提供了對面向服務(wù)的體系結(jié)構(gòu)的持久化層的標準化訪問。數(shù)據(jù)訪問服務(wù) (DAS) 與服務(wù)數(shù)據(jù)對象 (SDO) 密切相關(guān),因此要了解 DAS 的概念,首先需要了解一下 SDO。
在本文講述的高級部分,將給出一個端到端的示例應(yīng)用程序,該應(yīng)用程序使用適合開發(fā)人員和架構(gòu)師使用的 JDBC DAS。該示例使用 XML 對象關(guān)系映射信息保存對 SDO 對象圖的更改。(請參閱參考資料,以獲得有關(guān) SDO 的更多信息。)
什么是 SDO?
服務(wù)數(shù)據(jù)對象(Service Data Objects,SDO)是一項新興標準,用于表示企業(yè)應(yīng)用程序中的數(shù)據(jù)。SDO 是信息的容器,設(shè)計用于提升開放標準和互操作性。SDO 提供了在整個企業(yè)應(yīng)用程序中表示信息的方法,包括表示層、業(yè)務(wù)邏輯層和此類層之間的通信,如圖 1 所示。
圖 1. SDO 概述
服務(wù)數(shù)據(jù)對象的主要特性包括:
-
SDO 可以包含嵌套對象。此功能稱為對象圖,是一種非常靈活的表示數(shù)據(jù)的方式。例如,圖 2 中的 SDO 就表示一個有各種產(chǎn)品的多個訂單的客戶:
圖 2. SDO 數(shù)據(jù)圖
-
SDO 支持 XPath,可以訪問其封裝的數(shù)據(jù)。XML 路徑語言 (XPath) 是一項開放標準,是由 World Wide Web Consortium (W3C) 制定的,用于從 XML 文檔訪問數(shù)據(jù)。例如,可以使用以下字符串訪問特定的產(chǎn)品:CustomerOrder/Product[name='MP3Player']
,其中,CustomerOrder 為 Customer 和 Order 之間定義的關(guān)系。
-
SDO 可以作為 XML 構(gòu)件或 Java? 對象存在。借助對 XML 的這項透明支持,直接使用 <datagraph> 標記作為開頭來傳遞 XML SDO,就可以通過 Web 服務(wù)(或任何 XML 傳輸,如 REST 或 XML-RPC)傳遞 SDO。而且,僅在 SDO v1 中使用更改摘要時,才有必要使用 <datagraph> 標記。在其他所有情況下,可以使用任何標記。
-
SDO 包含更改摘要。SDO 更改摘要作為所有活動的歷史記錄使用,通過使用此功能,應(yīng)用程序可以將舊數(shù)據(jù)和新數(shù)據(jù)區(qū)分開。例如,加入某個客戶決定下新訂單。接受訂單的企業(yè)系統(tǒng)由圖 3 中的高級組件組成。請注意,包含新訂單的 SDO 將從門戶服務(wù)器傳遞到后端服務(wù)。如果沒有更改摘要,后端服務(wù)必須將 SDO 中的所有數(shù)據(jù)放入數(shù)據(jù)庫。不過,由于可以訪問 SDO 更改摘要,因此,只需要將新數(shù)據(jù)放入數(shù)據(jù)庫即可,從而提高后端服務(wù)的效率。此外,門戶服務(wù)器可以通過使用更改摘要來傳遞更小的 SDO,該 SDO 中僅包含在前端所做的更改。
圖 3. 更改摘要
-
SDO 是開放標準。SDO 1.0 和 2.0 規(guī)范均是由 BEA? 和 IBM 聯(lián)合發(fā)布的(請參閱參考資料)。任何組織都可以免費使用和實現(xiàn)這些標準。
什么是 DAS?
數(shù)據(jù)訪問服務(wù) (Data Access Service) 根據(jù) SDO 1.0 標準保存 SDO。DAS 可以采用任何持久化機制實現(xiàn)。例如,Rational Application Developer V6 包括了一個 JDBC DAS 和一個 EJB 實體 Bean DAS,允許采用標準方式將 SDO 保存到各種后端系統(tǒng),從而提升企業(yè)應(yīng)用程序內(nèi)的互操作性和標準。
圖 4. DAS 概述
DAS 是一項新興的規(guī)范,其標準化進程仍在進行之中?,F(xiàn)在稱為 DAS 的新一輪工作就是即將推出的數(shù)據(jù)訪問服務(wù) (DAS) 標準。可以將 DAS 稱為 DAS 2.0。DAS 將對 SDO 2.0 規(guī)范形成補充,正在制定之中(DAS 被認為處于 SDO 2.0 規(guī)范之外)。
面向服務(wù)的體系結(jié)構(gòu)中的數(shù)據(jù)訪問服務(wù)
SDO 數(shù)據(jù)訪問服務(wù)非常適合作為 SOA 服務(wù)公開。他們提供了一個標準,用于構(gòu)建可以在 SOA 服務(wù)間共享的后端服務(wù)。例如,假如有一個必須和兩個不同業(yè)務(wù)進行通信的企業(yè)系統(tǒng)。這兩個業(yè)務(wù)服務(wù)使用完全不同的技術(shù)保存信息。如果傳遞給這些服務(wù)的消息為 SDO,則兩個服務(wù)都可以使用 DAS,企業(yè)應(yīng)用程序可以將其看作同一個組織而進行處理,如圖 5 中所示。
圖 5. SOA 中的 SDO 數(shù)據(jù)訪問服務(wù)
DAS 還可以提高 SOA 的可維護性。實現(xiàn) SOA 的一個常見毛病就是會假設(shè)公開服務(wù)總是有好處的。當(dāng)公開了服務(wù)時,要更改非常困難——對于那些向客戶或公眾公開某種功能的服務(wù)更是如此。例如,假設(shè)某家銀行有一項已公開了數(shù)年的服務(wù),由于政府法規(guī)的原因,現(xiàn)在必須對其進行更改——在網(wǎng)上傳輸?shù)南⒈仨毥?jīng)過加密,如圖 6 中所示。
圖 6. SOA 中的 DAS 和可維護性
如果有數(shù)百合作伙伴訪問該服務(wù),該銀行不會輕易更改服務(wù),因為其合作伙伴將不再能與他們開展業(yè)務(wù)。該銀行的最佳選擇可能就是構(gòu)建另一個 99% 冗余的服務(wù),并盡力說服其合作伙伴轉(zhuǎn)而使用新服務(wù)。這將使用大量資源,而所得到的業(yè)務(wù)價值也有限。
將 SDO 和 DAS 配合使用,可以減緩這類問題,因為 SDO 是動態(tài)性非常強的消息。如果該銀行使用的是 SDO,則可以直接通知其合作伙伴對添加的信息進行加密,而不會更改已公開的服務(wù)——只需要更改傳遞給該服務(wù)的消息。如果某個合作伙伴仍然發(fā)送舊 SDO XML 格式的消息,通過檢查 SDO 的內(nèi)容(并可能與不兼容的業(yè)務(wù)合作伙伴聯(lián)系),銀行的應(yīng)用程序?qū)⒛軌驅(qū)Υ祟惽闆r作出判斷,然后按照以前的方式處理此類信息。
使用 SDO 數(shù)據(jù)訪問服務(wù)的業(yè)務(wù)案例
在現(xiàn)有持久化技術(shù)的基礎(chǔ)上將 SDO 和 DAS 結(jié)合使用,除了 SOA 的好處之外,其業(yè)務(wù)價值何在呢?請考慮以下管理方面的特征:
-
SDO 是一項開放標準。由于 SDO 是一項公開的標準,因此不會出現(xiàn)不得不選用某個供應(yīng)商的情況。截至本文發(fā)布時,BEA、IBM、Versant、Versata 和 XCalia 均推出了 SDO 實現(xiàn)。同樣,也已計劃對 SDO 的數(shù)據(jù)訪問進行標準化。
-
SDO 和 DAS 可以減少業(yè)務(wù)所必須維護的代碼量。數(shù)據(jù)訪問服務(wù)提供了一種標準的方法,用于保存封裝在 SDO 中的信息,而不受后端系統(tǒng)的影響(不管此后端系統(tǒng)是使用 JDBC 訪問的關(guān)系數(shù)據(jù)庫、使用視圖 Bean 訪問的 LDAP 服務(wù)器或是具有 DAS 實現(xiàn)的其他后端系統(tǒng))。實際上,為了使用異構(gòu)后端系統(tǒng)而編寫的自定義代碼與數(shù)據(jù)訪問服務(wù)采用標準的方式進行了整合。需要維護的代碼較少,通常可以盡可能減少潛在的缺陷,從而縮短投入市場的時間和減少風(fēng)險。
-
將 SDO 和 DAS 結(jié)合使用,不需要受具體的持久化技術(shù)限制。DAS 不僅使應(yīng)用程序無需依賴于數(shù)據(jù)庫或操作系統(tǒng),而且還使應(yīng)用程序獨立于整個持久化技術(shù)。通過使用多個數(shù)據(jù)訪問服務(wù),應(yīng)用程序可以支持這些中介的基礎(chǔ)持久化機制,而不用更改業(yè)務(wù)邏輯或呈現(xiàn)邏輯。對于 IT 環(huán)境復(fù)雜的組織,這樣可以減少成本、整合資產(chǎn),并可以減少將來進行高成本技術(shù)更改的風(fēng)險。
-
使用 SDO 和 DAS 有得有失。這兩項均是新興技術(shù),尚處于早期發(fā)布階段。很多數(shù)據(jù)訪問服務(wù)可能不支持其他持久化技術(shù)的最先進功能(除非 DAS 專門為支持該技術(shù)而構(gòu)建)。例如,IBM 的 JDBC Data Access Service 就尚不支持 SDO 表群集環(huán)境的分布式緩存。另外,若要充分發(fā)揮 SDO 和 DAS 的潛力,可能需要對各種新技術(shù)有所了解,包括 Web 服務(wù)、XPath 及 SDO 規(guī)范。對于開發(fā)組織,可以需要進行培訓(xùn)。
|
|
按部就班,使用 JDBC Data Access Service
本文剩下的部分將給出一個實例應(yīng)用程序的實現(xiàn)。就功能而言,CloseOrderApplication 將使用 Rational Application Developer V6 包含的 JDBC DAS 關(guān)閉客戶的訂單。該應(yīng)用程序?qū)臄?shù)據(jù)庫檢索一個 SDO 對象圖,對其進行更小,然后保存更改。將數(shù)據(jù)庫架構(gòu)映射到 SDO 對象圖的元數(shù)據(jù)是使用 XML 編寫的。
JDBC DAS 編程模型
圖 7 所示的關(guān)系圖演示了使用 JDBC Data Access Service 開發(fā)應(yīng)用程序時應(yīng)該有用的編程模型。
圖 7. JDBC DAS 編程模型
|
關(guān)于示例應(yīng)用程序
此示例不僅是試驗性的代碼,因為其中實現(xiàn)了 JavaEE 最佳實踐和實際錯誤處理。如果確實需要利用 JDBC Data Access Service 的代碼(通常不過寥寥幾行而已),清單 1 和清單 6 無疑是最為相關(guān)的了。數(shù)據(jù)庫設(shè)置、JavaEE 數(shù)據(jù)源定義、XML 元數(shù)據(jù)的 JNDI 查詢以及異常處理均屬于 JavaEE 開發(fā)期間要做的工作,而不屬于 SDO JDBC DAS。 |
|
在此模型中,JDBC DAS 使用 ConnectionWrapper 對 JDBC Connection 加以包裝,以連接到數(shù)據(jù)存儲區(qū)。使用 MetadataFactory 創(chuàng)建了 Metadata 的實例。然后使用各種構(gòu)造(如 Tables、Columns 及 Relationships)定義元數(shù)據(jù)。數(shù)據(jù)庫查詢的等效項在元數(shù)據(jù)中定義為篩選器。不過,在此示例中,元數(shù)據(jù)、表、列、關(guān)系和篩選器均在元數(shù)據(jù)中定義,且在 XML 映射文檔需要時透明地創(chuàng)建。(請參閱參考資料,以了解如何如上所示,在運行時使用元數(shù)據(jù) API。)定義了元數(shù)據(jù)后,就會將其與 ConnectionWrapper 一起使用,以創(chuàng)建 JDBCAccess。中介可以獲取和保存 SDO DataObject 圖。
我們將通過執(zhí)行以下任務(wù)來實現(xiàn)此實例應(yīng)用程序:
-
創(chuàng)建 JaveEE 項目
-
設(shè)置數(shù)據(jù)庫
-
定義 XML 元數(shù)據(jù)
-
創(chuàng)建方法
-
創(chuàng)建 JDBC 連接包裝類
-
創(chuàng)建 JDBC 中介
-
從數(shù)據(jù)庫檢索 SDO DataObject 圖
-
保存 SDO 圖
-
關(guān)閉連接
-
檢查應(yīng)用程序異常
-
使用 Servlet 測試應(yīng)用程序
示例應(yīng)用程序的先決條件
-
IBM Rational Application Developer for WebSphere Software V6.0 或更高版本。此外,為了運行此示例,需要 IBM WebSphere Application Server 的集成測試環(huán)境。可以下載 Rational Application Developer 的 30 天免費試用版。
-
IBM DB2 UDB V8.0 或更高版本。盡管可以使用任何兼容 JDBC 2.0 的數(shù)據(jù)庫,但此示例將使用 DB2 命令行處理程序設(shè)置數(shù)據(jù)庫,并在 WebSphere Application Server 中將 DB2 配置為數(shù)據(jù)源。可以下載 DB2 的 30 天試用版。
|
此示例假設(shè)為 SDO DAS 使用 JavaEE 環(huán)境。不過并不需要應(yīng)用程序服務(wù)器。IBM JDBC DAS 可以用于任何支持 Java SE 1.3 或更高版本的應(yīng)用程序中。 |
|
1. 創(chuàng)建 JavaEE 項目
在 Rational Application Developer 的 J2EE Perspective 中:
-
選擇 File => New => Enterprise Application Project。將其命名為 CloseOrder
,然后選擇 Finish。
-
右鍵單擊 CloseOrder,選擇 New => Dynamic Web Project,將其命名為 CloseOrderWeb
,然后單擊 Finish。
2. 設(shè)置數(shù)據(jù)庫
圖 8 顯示了示例應(yīng)用程序的數(shù)據(jù)庫架構(gòu)。其中包含一個 customer 條目和一個指向 order 條目的外鍵:
圖 8. 數(shù)據(jù)庫架構(gòu)
|
請注意,此處假設(shè)管理用戶名和密碼均為 db2admin 。
|
|
-
啟動 DB2 命令行處理程序。缺省情況下,可以采用以下方式啟動此工具:
-
Linux? 或 UNIX?:
- 作為數(shù)據(jù)庫管理員登錄(比如
su db2admin
)
- 鍵入
db2
并按 Enter。
-
Windows?:
- 選擇 Start => All Programs => IBM DB2 => Command Line Tools => Command Line Processor。
-
使用命令行處理程序執(zhí)行以下代碼:
清單 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 示例應(yīng)用程序?qū)?JDBC 數(shù)據(jù)庫使用 JNDI 上下文引用,以避免硬編碼數(shù)據(jù)庫連接信息。展開 CloseOrderWeb
,并雙擊 Deployment Descriptor: CloseOrderWeb。
-
選擇 Reference 選項卡,選擇 Add... => Resourse reference,然后輸入或選擇字段值,如圖 9 中所示。
圖 9. 數(shù)據(jù)源 JNDI 上下文引用
-
為 JNDI name 字段輸入 jdbc/db2/Example
,如圖 10 中所示。
圖 10. 數(shù)據(jù)庫 JNDI 名稱
3. 定義 XML 元數(shù)據(jù)
若要將數(shù)據(jù)架構(gòu)映射到 SDO 數(shù)據(jù)圖,則必須定義中介元數(shù)據(jù)。
圖 11. O/R 映射
可以在運行時使用 com.ibm.websphere.sdo.mediator.jdbc.metadata.Metadata 定義元數(shù)據(jù),圖 7 對此作了簡單描述(請參閱參考資料,以獲得關(guān)于在運行時定義元數(shù)據(jù)的文檔)。不過,我們的示例在 XML 中定義元數(shù)據(jù)。示例應(yīng)用程序?qū)⒃獢?shù)據(jù) XML 文件添加到類路徑中,從而簡化打開指向該文件的 java.io.InputStream 的過程,如要求創(chuàng)建中介時。
-
在 Rational Application Developer 中,右鍵單擊 CloseOrderWeb 項目,然后選擇 New => Source Folder。
-
輸入 xml
作為文件夾名稱,然后選擇 Finish。
-
右鍵單擊 CloseOrderWeb,然后選擇 Java Resources => metadata,再選擇 New => other... => Simple => Folder => Next。
-
將文件夾命名為 DAS
并選擇 Finish。
-
右鍵單擊 DAS 文件夾,然后采用類似的方式創(chuàng)建一個名為 metadata.xml
的新文件。
-
插入以下語句作為其內(nèi)容:
清單 2. 將元數(shù)據(jù)添加到 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 映射應(yīng)當(dāng)較為直觀。請考慮以下對某些其他元數(shù)據(jù)標記的描述:
-
<tables rootTable="CUSTOMER">
SDO 數(shù)據(jù)對象圖必須定義訪問的根入口點。在此應(yīng)用程序中 customer 就是根對象。
-
<queryInfo>
此標記定義篩選器。如果未定義篩選器,元數(shù)據(jù)將仍然有效;此時中介會將所有的客戶(以及所有相關(guān)訂單)作為 SDO 數(shù)據(jù)對象圖返回。此處定義的篩選器將 SDO 圖的返回縮小,使其僅包含與 filterArgument 匹配的客戶。當(dāng)中介從數(shù)據(jù)庫檢索此 SDO 圖時,將要求傳入一個名為 CUST_ID 的 int 類型參數(shù)。請注意,該參數(shù)并沒有設(shè)置 name = "CUST_ID"
,因為其可能與數(shù)據(jù)庫列名稱不同。
-
<relationships>
此標記定義 CUSTOMER.OPEN_ORDER_ID 的外鍵關(guān)系。在此關(guān)系中,customer 是子項,而 order 為父項。"Exclusive" 設(shè)置為 false,以指示中介檢索所有相關(guān)訂單,甚至包括沒有 customer 引用的 order。如果將其設(shè)置為 true,則僅檢索至少有一個子 customer 引用的 order 項。
(如果收到驗證錯誤“Element or attribute do not match QName
”,可以將其忽略。本文是入門級的文章,將不在 Rational Application Developer 內(nèi)設(shè)置驗證。)
-
示例應(yīng)用程序使用 JNDI 上下文引用查詢元數(shù)據(jù)文件的位置。這樣,應(yīng)用程序就可以避免對文件名稱進行硬編碼了。展開 CloseOrderWeb,然后雙擊 Deployment Descriptor: CloseOrderWeb。
-
選擇 Reference 選項卡,然后選擇 Add... => Resourse reference,并按照圖 12 所示填寫值。
圖 12. 元數(shù)據(jù)資源環(huán)境引用
-
在 JNDI name 字段中輸入 cell/persistent/string/CloseOrderMetadata
,如圖 13 所示。
圖 13. 元數(shù)據(jù) JNDI 名稱
4. 創(chuàng)建方法
現(xiàn)在已經(jīng)準備好,可以開始開發(fā)應(yīng)用程序的代碼了。
-
右鍵單擊 CloseOrderWeb 項目,并選擇 New => Class。
-
在 package 中輸入 developerworks.sdo.example
并將其命名為 CloseOrderApplication
。
為了更好地描述該應(yīng)用程序,將在接下來的每一步對 CloseOrderApplication 類的各個方法單獨進行討論。首先是該類的唯一公共方法 closeOrder(),該方法負責(zé)整個示例應(yīng)用程序的組織(圖 14)。
圖 14. CloseOrder 示例應(yīng)用程序的事件序列
以下方法是應(yīng)用程序的入口點,圖 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]
}
|
此方法的主要任務(wù)是:
-
獲取 JDBC 連接包裝類。
getConnectionWorker() 代碼詳細說明數(shù)據(jù)庫如何連接。輔助方法需要 JDBC 的 JNDI 上下文引用。
-
創(chuàng)建訪問。
輔助方法需要 ConnectionWrapper 和對 metadata.xml 的 JNDI 上下文引用。
-
獲取客戶的開放訂單。
輔助方法使用中介獲取 SDO 對象圖,遍歷到與根 customer 項相關(guān)的 order,然后將其返回。
-
處理無客戶的異常情況。
獲取開放訂單的輔助方法可能引發(fā) NoCustomer 異常。除了記錄此情況并通知表示層之外(使用 closeOrder() 進行),典型的異常處理還可能包括使用新連接重試,或嘗試采用名稱替代 ID 進行查找。
-
處理無開放訂單的異常情況。
獲取開放訂單的輔助方法可能引發(fā) OrderNotOpen 異常。對此的恰當(dāng)異常處理由讀者自行完成。
-
關(guān)閉訂單。
修改 order SDO DataObject 的狀態(tài)字符串。
-
保存訂單。
將 order SDO DataObject 保存到數(shù)據(jù)庫。
-
關(guān)閉連接。
關(guān)閉連接。
5. 創(chuàng)建 JDBC 連接包裝類
以下代碼示例包含創(chuàng)建數(shù)據(jù)庫連接的輔助方法。此方法完成了圖 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);
}
}
|
此方法的內(nèi)容對于具有 JDBC 經(jīng)驗的 JavaEE 開發(fā)人員非常簡單。唯一特定于 JDBC DAS 代碼是從 ConnectionWrapperFactory 創(chuàng)建 ConnectionWrapper。請注意,此處使用了一個泛型運行時異常重新引發(fā)假定將由 JavaEE 應(yīng)用程序中更高層處理的異常。
6. 創(chuàng)建 JDBC 中介
以下代碼示例包含創(chuàng)建中介的輔助方法。此方法完成了圖 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;
}
|
此方法的主要任務(wù)是:
-
使用 JNDI 上下文引用獲取文件名。
采用與查詢 JDBC 數(shù)據(jù)源類似的方法檢索 XML 元數(shù)據(jù)文件名。
-
創(chuàng)建文件流
使用文件名創(chuàng)建指向 XML 元數(shù)據(jù)文件的常規(guī) java.io.InputStream。
-
創(chuàng)建 JDBC 訪問。
使用 JDBCAccessFactory,并將文件流和數(shù)據(jù)庫連接包裝類作為參數(shù),以創(chuàng)建中介。
-
處理異常。
此處也是使用一個泛型運行時異常處理各種異常。
7. 從數(shù)據(jù)庫檢索 SDO DataObject 圖
以下代碼片段包含了從數(shù)據(jù)庫檢索 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]
}
|
此方法的主要任務(wù)是:
-
創(chuàng)建參數(shù)。
創(chuàng)建一個名為 CUST_ID 的參數(shù),并將其設(shè)置為 customerId
。此參數(shù)在篩選器中使用,以將 SDO 圖限制為僅包含具有元數(shù)據(jù) XML 中指定的特定 ID 的客戶。
-
獲取 SDO DataObject 圖。
使用步驟 1 中構(gòu)造的參數(shù)對中介調(diào)用 getGraph 方法。此圖中應(yīng)包含客戶及其相關(guān)訂單。
-
檢查客戶是否存在。
getList("CUSTOMER") 方法返回 SDO 圖中所有客戶數(shù)據(jù)對象的列表。如果大小為零,則將引發(fā) NoCustomer 應(yīng)用程序異常。
-
獲取客戶。
從 SDO 圖獲取客戶。請注意,追加到 CUSTOMER.0
的零是必需的,用以指示要檢索 customer 列表的哪個元素(在此例中,列表中僅有一個客戶)。
-
檢查是否存在開放訂單。
如果訂單不是開放狀態(tài),則不能對其進行關(guān)閉操作。將檢查 OPEN_ORDER_ID 外鍵,還將檢查 order DataObject 列表是否為非零。
-
返回開放訂單。
通過遍歷元數(shù)據(jù)中定義的關(guān)系,從 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. 關(guān)閉連接
以下代碼示例包含關(guān)閉數(shù)據(jù)庫連接的輔助方法。此代碼完成了圖 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. 檢查應(yīng)用程序異常
CloseOrderApplication 使用了以下異常,這些異常都位于 developerworks.sdo.example.exception 包內(nèi):
清單 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 測試應(yīng)用程序
-
右鍵單擊 Deployment Descriptor: CloseOrderWeb 項目,然后選擇 New => Servlet...。
-
在 Name 字段輸入 TestCloseOrder
,然后單擊 Next。
-
在 Java package 中輸入 developerworks.sdo.example.test
,然后單擊 Finish。
-
插入以下代碼作為 doGet
方法的內(nèi)容:
清單 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。
-
再次右鍵單擊服務(wù)器,并選擇 Add and remove projects...,以將 CloseOrder EAR 項目部署到服務(wù)器。
-
部署了項目之后,使用以下 URL 在 Web 瀏覽器中打開管理控制臺:http://localhost:9060/admin。
-
選擇 Log in => Security => Global security => JAAS Configuration => J2C Authentication data => New,并按照圖 15 所示填寫表單。
圖 15. 數(shù)據(jù)庫身份驗證入口
-
選擇 OK,然后選擇 Save。
-
選擇 Environment => WebSphere Variables => DB2UNIVERSAL_JDBC_DRIVER_PATH 并輸入您的 DB2 驅(qū)動程序目錄。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。
-
為了確保數(shù)據(jù)源正常工作,請選擇 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。
-
重新啟動服務(wù)器,以確保所有 JNDI 綁定均已更新。
-
若要運行該應(yīng)用程序,請將以下 URL 輸入到 Web 瀏覽器中:http://localhost:9080/CloseOrderWeb/TestCloseOrder?customerId=2
|
|
結(jié)束語
JDBC Data Access Service 提供了對面向服務(wù)的體系結(jié)構(gòu)的持久化層的標準化訪問。本文演示了 SDO DAS 如何如何適應(yīng)大型的企業(yè)部署,以及如何使用簡潔且用戶友好的 XML 元數(shù)據(jù)將現(xiàn)有數(shù)據(jù)庫架構(gòu)映射到 SDO。