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