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